├── .gitignore ├── LICENSE ├── README.md ├── dist ├── index.js └── lib │ ├── CLIApplication.js │ ├── CLIGlobal.js │ ├── CLIWidget.js │ └── CLIWidgets │ ├── CLIButton.js │ ├── CLICheckBox.js │ ├── CLIComboBox.js │ ├── CLIImage.js │ ├── CLILabel.js │ ├── CLIRadioButton.js │ └── CLITextBox.js ├── imgs └── intro.gif ├── package-lock.json ├── package.json ├── src ├── index.ts └── lib │ ├── CLIApplication.ts │ ├── CLIGlobal.ts │ └── CLIWidgets │ ├── CLIButton.ts │ ├── CLICheckBox.ts │ ├── CLIComboBox.ts │ ├── CLIImage.ts │ ├── CLILabel.ts │ └── CLIRadioButton.ts └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 ICe1 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NodeCLI - GUI 2 | 3 | From now on, you can use **CLI** as quickly and easily as **GUI**. 4 | 5 | ### Introduce 6 | 7 | The reason why I made this project. 8 | 9 | - [NodeOS](https://github.com/ICe1BotMaker/node-os). It's a project to create an operating system in a **Node** execution environment, and I made it because I thought it would be better to implement **CLI** in a similar way as **GUI**. 10 | 11 | Similarities to GUI? 12 | 13 | - You can control it with a keyboard. 14 | 15 | - It contains various widgets. 16 | 17 | - Allows the user to know what function it is. 18 | 19 | ### Preview Run Results 20 | 21 | 22 | 23 | ### Installation 24 | 25 | ``` 26 | $ npm install nodecli-gui 27 | ``` 28 | 29 | ### Examples 30 | 31 | Todo App: 32 | 33 | ```js 34 | import chalk from 'chalk'; 35 | 36 | import { CLIApplication, CLIButton, CLICheckBox, CLILabel } from 'nodecli-gui'; 37 | 38 | const app = new CLIApplication(); 39 | 40 | app.setWindowTitle(`Test Application`); 41 | app.setWindowIcon(`xampp-icon.ico`); 42 | 43 | 44 | // Title 45 | const title1 = new CLILabel({ text: `[ Todo List ]` }); 46 | app.addComponent(title1.return(), { x: 1, y: 1 }); 47 | 48 | 49 | // todos 50 | let todosText = [`To complete all tasks`, `Finish handling exceptions.`, `Commit to git.`]; 51 | 52 | todosText.forEach((text, idx) => { 53 | const item = new CLICheckBox({ text: `- ${text}`, beforeText: `✅ `, bool: idx === 2 }); 54 | item.on(`select`); 55 | app.addComponent(item.return(), { x: 1, y: 1 }); 56 | }); 57 | 58 | 59 | // modify button 60 | const modify = new CLIButton({ text: chalk.bgBlueBright(` modify `) }); 61 | modify.on(`select`, () => { 62 | app.selectedItems().forEach(item => { 63 | app.modifyText(item, { text: `- test todo` }); 64 | }); 65 | }); 66 | 67 | app.addComponent(modify.return(), { x: 1, y: 1 }); 68 | 69 | 70 | // remove button 71 | const remove = new CLIButton({ text: chalk.bgRedBright(` remove `) }); 72 | remove.on(`select`, () => { 73 | app.selectedItems().forEach(item => { 74 | app.remove(item); 75 | }); 76 | }); 77 | 78 | app.addComponent(remove.return(), { x: 10, y: -1 }); 79 | 80 | 81 | app.show(10); 82 | ``` 83 | -------------------------------------------------------------------------------- /dist/index.js: -------------------------------------------------------------------------------- 1 | export { CLIGlobal } from './lib/CLIGlobal.js'; 2 | export { CLIApplication } from './lib/CLIApplication.js'; 3 | export { CLILabel } from './lib/CLIWidgets/CLILabel.js'; 4 | export { CLIButton } from './lib/CLIWidgets/CLIButton.js'; 5 | export { CLICheckBox } from './lib/CLIWidgets/CLICheckBox.js'; 6 | export { CLIRadioButton } from './lib/CLIWidgets/CLIRadioButton.js'; 7 | export { CLIImage } from './lib/CLIWidgets/CLIImage.js'; 8 | // export { CLIComboBox } from './lib/CLIWidgets/CLIComboBox.js'; 9 | -------------------------------------------------------------------------------- /dist/lib/CLIApplication.js: -------------------------------------------------------------------------------- 1 | import chalk from 'chalk'; 2 | import { exec } from 'child_process'; 3 | import { readFileSync, writeFileSync } from 'fs'; 4 | import { CLIGlobal } from './CLIGlobal.js'; 5 | /** 6 | * CLI Application 7 | */ 8 | export class CLIApplication extends CLIGlobal { 9 | constructor() { 10 | super(); 11 | this.components = []; 12 | this.agent = { 13 | x: 0 14 | }; 15 | } 16 | find(obj) { 17 | let result; 18 | this.components.forEach((component, idx) => { 19 | if (obj?.name) { 20 | if (component.name === obj.name) 21 | result = idx; 22 | } 23 | else if (obj?.id) { 24 | if (component.id === obj.id) 25 | result = idx; 26 | } 27 | }); 28 | return result; 29 | } 30 | remove(obj) { 31 | this.components.splice(this.find(obj), 1); 32 | } 33 | modifyText(obj, { text }) { 34 | this.components[this.find(obj)].text = text; 35 | } 36 | selectedItems(type = `checkbox`, { name } = { name: undefined }) { 37 | let result = []; 38 | this.components.forEach((component, idx) => { 39 | if (type === `checkbox`) { 40 | if (component.type === `checkbox` && component.toggleState) { 41 | result = [...result, component]; 42 | } 43 | } 44 | else if (type === `radiobutton`) { 45 | if (component.type === `radiobutton` && component.toggleState && component.name === name) { 46 | result = [...result, component]; 47 | } 48 | } 49 | }); 50 | return result; 51 | } 52 | addComponent(component, { x = 0, y = 0 }) { 53 | component.x = x; 54 | component.y = y; 55 | this.components = [...this.components, component]; 56 | } 57 | show(time = 100) { 58 | process.stdin.setRawMode(true); 59 | process.stdin.setEncoding(`utf-8`); 60 | process.stdin.on(`data`, (key) => { 61 | if (key === `\u0003`) { 62 | console.clear(); 63 | process.stdout.write(`\x1B[?25h`); 64 | process.exit(); 65 | } 66 | if (key === `\u001b[D`) 67 | this.agent.x -= 1; 68 | if (key === `\u001B[C`) 69 | this.agent.x += 1; 70 | if (key === `\r` || key === `\n`) { 71 | this.components.forEach(component => { 72 | if (component?.type === `combobox` && this.find({ name: component.id }) === undefined) { 73 | component.items.forEach(item => { 74 | this.addComponent(item, { x: item.x, y: item.y }); 75 | }); 76 | } 77 | }); 78 | this.components.forEach((component, idx) => { 79 | if (this.agent.x === idx) { 80 | if (component?.selectEvent) { 81 | component.selectEvent(); 82 | if (component?.type === `checkbox`) { 83 | component.toggleState = !component.toggleState; 84 | } 85 | else if (component?.type === `radiobutton`) { 86 | this.selectedItems(`radiobutton`, { name: component.name }).forEach(item => { 87 | item.toggleState = false; 88 | }); 89 | component.toggleState = true; 90 | } 91 | else if (component?.type === `combobox`) { 92 | component.toggleState = !component.toggleState; 93 | } 94 | } 95 | } 96 | }); 97 | } 98 | if (this.agent.x === -1) 99 | this.agent.x = 0; 100 | if (this.agent.x === this.components.length) 101 | this.agent.x = this.components.length - 1; 102 | }); 103 | process.stdout.write(`\x1B[?25l`); 104 | setInterval(() => { 105 | console.clear(); 106 | this.components.forEach((component, idx) => { 107 | this.moveCursor({ x: component.x, y: component.y }); 108 | if (this.agent.x === idx && (component?.pickEvent || component?.selectEvent || component?.changeEvent)) { 109 | if ([`checkbox`, `radiobutton`].includes(component.type) && component?.toggleState === true) { 110 | console.log(`${component.beforeText}${chalk.italic.bold.overline.underline(component.text)}`); 111 | } 112 | else if (component?.type === `combobox` && component?.toggleState === true) { 113 | console.log(chalk.italic.bold.overline.underline(component.text)); 114 | } 115 | else { 116 | console.log(chalk.italic.bold.overline.underline(component.text)); 117 | } 118 | if (component?.pickEvent) 119 | component.pickEvent(); 120 | } 121 | else { 122 | if ([`checkbox`, `radiobutton`].includes(component.type) && component?.toggleState === true) { 123 | console.log(`${component.beforeText}${component.text}`); 124 | } 125 | else { 126 | console.log(component.text); 127 | } 128 | } 129 | }); 130 | }, time); 131 | } 132 | setWindowTitle(title) { 133 | const config = JSON.parse(readFileSync(`./pkg-config.json`, `utf-8`)); 134 | config.win.title = title.trim(); 135 | writeFileSync(`./pkg-config.json`, JSON.stringify(config, null, 4)); 136 | } 137 | setWindowIcon(path) { 138 | const config = JSON.parse(readFileSync(`./pkg-config.json`, `utf-8`)); 139 | config.icon = path.trim(); 140 | writeFileSync(`./pkg-config.json`, JSON.stringify(config, null, 4)); 141 | } 142 | compile() { 143 | exec(`pkg . -c pkg-config.json`, { cwd: `./` }); 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /dist/lib/CLIGlobal.js: -------------------------------------------------------------------------------- 1 | import chalk from 'chalk'; 2 | import { moveCursor } from 'readline'; 3 | /** 4 | * CLI Global 5 | */ 6 | export class CLIGlobal { 7 | constructor() { } 8 | moveCursor({ x, y }) { 9 | moveCursor(process.stdout, x, y); 10 | } 11 | throwError({ code, message }) { 12 | throw new Error(`(code: ${code}) ${chalk.redBright.underline(message)}`); 13 | } 14 | generateId() { 15 | return Math.random().toString(36).substring(2) + Math.random().toString(36).substring(2); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /dist/lib/CLIWidget.js: -------------------------------------------------------------------------------- 1 | import { CLIGlobal } from './CLIGlobal.js'; 2 | /** 3 | * CLI Widget 4 | */ 5 | export class CLIWidget extends CLIGlobal { 6 | constructor() { super(); } 7 | /** 8 | * @param {'pick' | 'select'} type 9 | */ 10 | on(type, event) { 11 | if (type === `pick`) 12 | this.pickEvent = event; 13 | if (type === `select`) 14 | this.selectEvent = event; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /dist/lib/CLIWidgets/CLIButton.js: -------------------------------------------------------------------------------- 1 | import { CLIGlobal } from '../CLIGlobal.js'; 2 | /** 3 | * CLI Button 4 | */ 5 | export class CLIButton extends CLIGlobal { 6 | constructor({ text }) { 7 | super(); 8 | this.labelText = text; 9 | this.id = this.generateId(); 10 | } 11 | /** 12 | * @param {'pick' | 'select'} type 13 | */ 14 | on(type, event = () => { }) { 15 | if (type === `pick`) 16 | this.pickEvent = event; 17 | if (type === `select`) 18 | this.selectEvent = event; 19 | } 20 | return() { 21 | return { 22 | type: `button`, 23 | id: this.id, 24 | text: this.labelText, 25 | pickEvent: this.pickEvent, 26 | selectEvent: this.selectEvent 27 | }; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /dist/lib/CLIWidgets/CLICheckBox.js: -------------------------------------------------------------------------------- 1 | import { CLIGlobal } from '../CLIGlobal.js'; 2 | /** 3 | * CLI CheckBox 4 | */ 5 | export class CLICheckBox extends CLIGlobal { 6 | constructor({ text, bool = false, beforeText = `✅` }) { 7 | super(); 8 | this.labelText = text; 9 | this.id = this.generateId(); 10 | this.toggleState = bool; 11 | this.beforeText = beforeText; 12 | } 13 | /** 14 | * @param {'pick' | 'select'} type 15 | */ 16 | on(type, event = () => { }) { 17 | if (type === `pick`) 18 | this.pickEvent = event; 19 | if (type === `select`) 20 | this.selectEvent = event; 21 | } 22 | return() { 23 | return { 24 | type: `checkbox`, 25 | id: this.id, 26 | text: this.labelText, 27 | beforeText: this.beforeText, 28 | pickEvent: this.pickEvent, 29 | selectEvent: this.selectEvent, 30 | toggleState: this.toggleState 31 | }; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /dist/lib/CLIWidgets/CLIComboBox.js: -------------------------------------------------------------------------------- 1 | import { CLIGlobal } from '../CLIGlobal.js'; 2 | /** 3 | * CLI ComboBox 4 | */ 5 | export class CLIComboBox extends CLIGlobal { 6 | constructor({ text, bool = false, beforeText = `✅` }) { 7 | super(); 8 | this.labelText = text; 9 | this.id = this.generateId(); 10 | this.items = []; 11 | this.toggleState = bool; 12 | this.beforeText = beforeText; 13 | } 14 | addItem(item, { x = 0, y = 0 }) { 15 | item.name = this.id; 16 | item.x = x; 17 | item.y = y; 18 | this.items = [...this.items, item]; 19 | } 20 | /** 21 | * @param {'pick' | 'select' | 'change'} type 22 | */ 23 | on(type, event = () => { }) { 24 | if (type === `pick`) 25 | this.pickEvent = event; 26 | if (type === `select`) 27 | this.selectEvent = event; 28 | if (type === `change`) 29 | this.changeEvent = event; 30 | } 31 | return() { 32 | return { 33 | type: `combobox`, 34 | id: this.id, 35 | text: this.labelText, 36 | beforeText: this.beforeText, 37 | pickEvent: this.pickEvent, 38 | selectEvent: this.selectEvent, 39 | changeEvent: this.changeEvent, 40 | items: this.items 41 | }; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /dist/lib/CLIWidgets/CLIImage.js: -------------------------------------------------------------------------------- 1 | // @ts-ignore 2 | import { CLIGlobal } from '../CLIGlobal.js'; 3 | import * as Jimp from 'jimp'; 4 | /** 5 | * CLI Image 6 | */ 7 | export class CLIImage extends CLIGlobal { 8 | constructor(url, { width, height }) { 9 | super(); 10 | this.Jimp = Jimp; 11 | this.image(url, width, height).then(data => { 12 | this.text = data; 13 | this.return(); 14 | }); 15 | this.id = this.generateId(); 16 | } 17 | async image(path, width, height) { 18 | const image = await this.Jimp.default.read(path); 19 | image.resize(width, height); 20 | let asciiArt = ``; 21 | image.scan(0, 0, image.getWidth(), image.getHeight(), (x, y, idx) => { 22 | const red = image.bitmap.data[idx + 0]; 23 | const green = image.bitmap.data[idx + 1]; 24 | const blue = image.bitmap.data[idx + 2]; 25 | const asciiChar = red < 128 ? `#` : `-`; 26 | const textColor = `\x1b[38;2;${red};${green};${blue}m`; 27 | const resetColor = `\x1b[0m`; 28 | asciiArt += textColor + asciiChar + resetColor; 29 | if (x === image.getWidth() - 1) 30 | asciiArt += `\n`; 31 | }); 32 | return asciiArt; 33 | } 34 | return() { 35 | return { 36 | type: `image`, 37 | id: this.id, 38 | text: this.text 39 | }; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /dist/lib/CLIWidgets/CLILabel.js: -------------------------------------------------------------------------------- 1 | import { CLIGlobal } from '../CLIGlobal.js'; 2 | /** 3 | * CLI Label 4 | */ 5 | export class CLILabel extends CLIGlobal { 6 | constructor({ text }) { 7 | super(); 8 | this.labelText = text; 9 | this.id = this.generateId(); 10 | } 11 | return() { 12 | return { 13 | type: `label`, 14 | id: this.id, 15 | text: this.labelText 16 | }; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /dist/lib/CLIWidgets/CLIRadioButton.js: -------------------------------------------------------------------------------- 1 | import { CLIGlobal } from '../CLIGlobal.js'; 2 | /** 3 | * CLI RadioButton 4 | */ 5 | export class CLIRadioButton extends CLIGlobal { 6 | constructor({ text, name, bool = false, beforeText = `✅` }) { 7 | super(); 8 | this.labelText = text; 9 | this.id = this.generateId(); 10 | this.toggleState = bool; 11 | this.beforeText = beforeText; 12 | this.name = name; 13 | } 14 | /** 15 | * @param {'pick' | 'select'} type 16 | */ 17 | on(type, event = () => { }) { 18 | if (type === `pick`) 19 | this.pickEvent = event; 20 | if (type === `select`) 21 | this.selectEvent = event; 22 | } 23 | return() { 24 | return { 25 | type: `radiobutton`, 26 | id: this.id, 27 | name: this.name, 28 | text: this.labelText, 29 | beforeText: this.beforeText, 30 | pickEvent: this.pickEvent, 31 | selectEvent: this.selectEvent, 32 | toggleState: this.toggleState 33 | }; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /dist/lib/CLIWidgets/CLITextBox.js: -------------------------------------------------------------------------------- 1 | import { CLIGlobal } from '../CLIGlobal.js'; 2 | /** 3 | * CLI TextBox 4 | */ 5 | export class CLITextBox extends CLIGlobal { 6 | constructor({ text = `` }) { 7 | super(); 8 | this.text = text; 9 | this.focus = false; 10 | this.id = Math.random().toString(36).substring(2); 11 | } 12 | /** 13 | * @param {'pick' | 'select'} type 14 | */ 15 | on(type, event = () => { }) { 16 | if (type === `pick`) 17 | this.pickEvent = event; 18 | if (type === `select`) 19 | this.selectEvent = event; 20 | } 21 | return() { 22 | return { 23 | type: `textbox`, 24 | id: this.id, 25 | text: this.text, 26 | pickEvent: this.pickEvent, 27 | selectEvent: this.selectEvent, 28 | focus: this.focus 29 | }; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /imgs/intro.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ICe1BotMaker/nodecli-gui/0a94a0e4bf8c3a1f2334eecff37fd1ee6a2845d2/imgs/intro.gif -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nodecli-gui", 3 | "version": "1.0.11", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "nodecli-gui", 9 | "version": "1.0.11", 10 | "license": "MIT", 11 | "dependencies": { 12 | "@types/node": "^20.3.0", 13 | "chalk": "^5.2.0", 14 | "child_process": "^1.0.2", 15 | "jimp": "^0.22.8", 16 | "readline": "^1.3.0", 17 | "typescript": "^5.1.3" 18 | }, 19 | "devDependencies": { 20 | "@types/jimp": "^0.2.28" 21 | } 22 | }, 23 | "node_modules/@jimp/bmp": { 24 | "version": "0.22.8", 25 | "resolved": "https://registry.npmjs.org/@jimp/bmp/-/bmp-0.22.8.tgz", 26 | "integrity": "sha512-JEMKgM1AEvvWfn9ZCHn62nK+QCE3Pb/ZhPdL3NF0ZgKNww6pqOmo6KqXzqY18JLB7c0epuTp4GPDPDhOh/ou1g==", 27 | "dependencies": { 28 | "@jimp/utils": "^0.22.8", 29 | "bmp-js": "^0.1.0" 30 | }, 31 | "peerDependencies": { 32 | "@jimp/custom": ">=0.3.5" 33 | } 34 | }, 35 | "node_modules/@jimp/core": { 36 | "version": "0.22.8", 37 | "resolved": "https://registry.npmjs.org/@jimp/core/-/core-0.22.8.tgz", 38 | "integrity": "sha512-vkN28aFikzQieA6bGxN+qe20pseCAemCyUI0YmRkJIArlb6OujtAwWAKyokv2lylV56bq8EQGIz+Y30OXUnRqg==", 39 | "dependencies": { 40 | "@jimp/utils": "^0.22.8", 41 | "any-base": "^1.1.0", 42 | "buffer": "^5.2.0", 43 | "exif-parser": "^0.1.12", 44 | "file-type": "^16.5.4", 45 | "isomorphic-fetch": "^3.0.0", 46 | "mkdirp": "^2.1.3", 47 | "pixelmatch": "^4.0.2", 48 | "tinycolor2": "^1.6.0" 49 | } 50 | }, 51 | "node_modules/@jimp/custom": { 52 | "version": "0.22.8", 53 | "resolved": "https://registry.npmjs.org/@jimp/custom/-/custom-0.22.8.tgz", 54 | "integrity": "sha512-u6lP9x/HNeGHB0Oojv4c2mhuDvn7G0ikzYbK4IKLsH4HzHxt62faMjBzQMcFhKJhR6UiiKE/jiHrhGvBT/fMkw==", 55 | "dependencies": { 56 | "@jimp/core": "^0.22.8" 57 | } 58 | }, 59 | "node_modules/@jimp/gif": { 60 | "version": "0.22.8", 61 | "resolved": "https://registry.npmjs.org/@jimp/gif/-/gif-0.22.8.tgz", 62 | "integrity": "sha512-I0l6koS67IPU40RPxCJTD1NvePEd8vUIHTejx1ly0jrjGnumbqdarAlBUkDrKfPPc+Fnqp84hBbSN1w5hNPT6w==", 63 | "dependencies": { 64 | "@jimp/utils": "^0.22.8", 65 | "gifwrap": "^0.9.2", 66 | "omggif": "^1.0.9" 67 | }, 68 | "peerDependencies": { 69 | "@jimp/custom": ">=0.3.5" 70 | } 71 | }, 72 | "node_modules/@jimp/jpeg": { 73 | "version": "0.22.8", 74 | "resolved": "https://registry.npmjs.org/@jimp/jpeg/-/jpeg-0.22.8.tgz", 75 | "integrity": "sha512-hLXrQ7/0QiUhAVAF10dfGCSq3hvyqjKltlpu/87b3wqMDKe9KdvhX1AJHiUUrAbJv1fAcnOmQGTyXGuySa1D6A==", 76 | "dependencies": { 77 | "@jimp/utils": "^0.22.8", 78 | "jpeg-js": "^0.4.4" 79 | }, 80 | "peerDependencies": { 81 | "@jimp/custom": ">=0.3.5" 82 | } 83 | }, 84 | "node_modules/@jimp/plugin-blit": { 85 | "version": "0.22.8", 86 | "resolved": "https://registry.npmjs.org/@jimp/plugin-blit/-/plugin-blit-0.22.8.tgz", 87 | "integrity": "sha512-rQ19txVCKIwo74HtgFodFt4//0ATPCJK+f24riqzb+nx+1JaOo1xRvpJqg4moirHwKR2fhwdDxmY7KX20kCeYA==", 88 | "dependencies": { 89 | "@jimp/utils": "^0.22.8" 90 | }, 91 | "peerDependencies": { 92 | "@jimp/custom": ">=0.3.5" 93 | } 94 | }, 95 | "node_modules/@jimp/plugin-blur": { 96 | "version": "0.22.8", 97 | "resolved": "https://registry.npmjs.org/@jimp/plugin-blur/-/plugin-blur-0.22.8.tgz", 98 | "integrity": "sha512-GWbNK3YW6k2EKiGJdpAFEr0jezPBtiVxj2wG/lCPuWJz7KmzSSN99hQjIy73xQxoBCRdALfJlkhe3leFNRueSQ==", 99 | "dependencies": { 100 | "@jimp/utils": "^0.22.8" 101 | }, 102 | "peerDependencies": { 103 | "@jimp/custom": ">=0.3.5" 104 | } 105 | }, 106 | "node_modules/@jimp/plugin-circle": { 107 | "version": "0.22.8", 108 | "resolved": "https://registry.npmjs.org/@jimp/plugin-circle/-/plugin-circle-0.22.8.tgz", 109 | "integrity": "sha512-qPCw8XFW8opT89ciFDuvs+eB3EB1mZIJWVajD2qAlprHiE7YGr34TkM7N5MNr3qZ1pJgkYdW6+HbBrJwBaonqw==", 110 | "dependencies": { 111 | "@jimp/utils": "^0.22.8" 112 | }, 113 | "peerDependencies": { 114 | "@jimp/custom": ">=0.3.5" 115 | } 116 | }, 117 | "node_modules/@jimp/plugin-color": { 118 | "version": "0.22.8", 119 | "resolved": "https://registry.npmjs.org/@jimp/plugin-color/-/plugin-color-0.22.8.tgz", 120 | "integrity": "sha512-ogkbg6rpDVH/mMLgAQKg17z3oZE0VN7ZWxNoH12fUHchqKz1I57zpa65fxZe2I8T5Xz97HR3x+7V7oI8qQGdSA==", 121 | "dependencies": { 122 | "@jimp/utils": "^0.22.8", 123 | "tinycolor2": "^1.6.0" 124 | }, 125 | "peerDependencies": { 126 | "@jimp/custom": ">=0.3.5" 127 | } 128 | }, 129 | "node_modules/@jimp/plugin-contain": { 130 | "version": "0.22.8", 131 | "resolved": "https://registry.npmjs.org/@jimp/plugin-contain/-/plugin-contain-0.22.8.tgz", 132 | "integrity": "sha512-oiaPLdJt9Dk+XEEhM/OU3lFemM51mA9NgMCAdburSCjDzKacJYBGFSHjTOhXzcxOie/ZDpOYN/UzFGKy8Dgl9A==", 133 | "dependencies": { 134 | "@jimp/utils": "^0.22.8" 135 | }, 136 | "peerDependencies": { 137 | "@jimp/custom": ">=0.3.5", 138 | "@jimp/plugin-blit": ">=0.3.5", 139 | "@jimp/plugin-resize": ">=0.3.5", 140 | "@jimp/plugin-scale": ">=0.3.5" 141 | } 142 | }, 143 | "node_modules/@jimp/plugin-cover": { 144 | "version": "0.22.8", 145 | "resolved": "https://registry.npmjs.org/@jimp/plugin-cover/-/plugin-cover-0.22.8.tgz", 146 | "integrity": "sha512-mO68w1m/LhfuHU8LKHY05a4/hhWnY4t+T+8JCw9t+5yfzA4+LofBZZKtFtWgwf/QGe1y3X2rtUU/avAzDUKyyA==", 147 | "dependencies": { 148 | "@jimp/utils": "^0.22.8" 149 | }, 150 | "peerDependencies": { 151 | "@jimp/custom": ">=0.3.5", 152 | "@jimp/plugin-crop": ">=0.3.5", 153 | "@jimp/plugin-resize": ">=0.3.5", 154 | "@jimp/plugin-scale": ">=0.3.5" 155 | } 156 | }, 157 | "node_modules/@jimp/plugin-crop": { 158 | "version": "0.22.8", 159 | "resolved": "https://registry.npmjs.org/@jimp/plugin-crop/-/plugin-crop-0.22.8.tgz", 160 | "integrity": "sha512-ns4oH0h0gezYsbuH8RThcMLY5uTLk/vnqOVjWCehMHEzxi0DHMWCmpcb6bC//vJ+XFNhtVGn1ALN7+ROmPrj+A==", 161 | "dependencies": { 162 | "@jimp/utils": "^0.22.8" 163 | }, 164 | "peerDependencies": { 165 | "@jimp/custom": ">=0.3.5" 166 | } 167 | }, 168 | "node_modules/@jimp/plugin-displace": { 169 | "version": "0.22.8", 170 | "resolved": "https://registry.npmjs.org/@jimp/plugin-displace/-/plugin-displace-0.22.8.tgz", 171 | "integrity": "sha512-Cj8nHYgsdFynOIx3dbbiVwRuZn3xO+RVfwkTRy0JBye+K2AU8SQJS+hSFNMQFTZt5djivh6kh0TzvR/6LkOd1w==", 172 | "dependencies": { 173 | "@jimp/utils": "^0.22.8" 174 | }, 175 | "peerDependencies": { 176 | "@jimp/custom": ">=0.3.5" 177 | } 178 | }, 179 | "node_modules/@jimp/plugin-dither": { 180 | "version": "0.22.8", 181 | "resolved": "https://registry.npmjs.org/@jimp/plugin-dither/-/plugin-dither-0.22.8.tgz", 182 | "integrity": "sha512-oE0Us/6bEgrgEg56plU3jSBzvB9iGhweKUHmxYMWnQbFCHP4mNCtPAs8+Fmq6c+m98ZgBgRcrJTnC7lphHkGyw==", 183 | "dependencies": { 184 | "@jimp/utils": "^0.22.8" 185 | }, 186 | "peerDependencies": { 187 | "@jimp/custom": ">=0.3.5" 188 | } 189 | }, 190 | "node_modules/@jimp/plugin-fisheye": { 191 | "version": "0.22.8", 192 | "resolved": "https://registry.npmjs.org/@jimp/plugin-fisheye/-/plugin-fisheye-0.22.8.tgz", 193 | "integrity": "sha512-bWvYY/nfMcKclWEaRyAir+YsT6C5St823HUQAsewZowTrJmme+w4U2a6InsryTHUL01BBcV5BLH0aDHuV3StvA==", 194 | "dependencies": { 195 | "@jimp/utils": "^0.22.8" 196 | }, 197 | "peerDependencies": { 198 | "@jimp/custom": ">=0.3.5" 199 | } 200 | }, 201 | "node_modules/@jimp/plugin-flip": { 202 | "version": "0.22.8", 203 | "resolved": "https://registry.npmjs.org/@jimp/plugin-flip/-/plugin-flip-0.22.8.tgz", 204 | "integrity": "sha512-0NFTNzjsdmOQkaIkNjZqO3/yU4SQb9nnWQXsLS1fFo+9QrIL5v8vVkXpk/rhiND6PyTj2mMTNjOa76GuZcC+iQ==", 205 | "dependencies": { 206 | "@jimp/utils": "^0.22.8" 207 | }, 208 | "peerDependencies": { 209 | "@jimp/custom": ">=0.3.5", 210 | "@jimp/plugin-rotate": ">=0.3.5" 211 | } 212 | }, 213 | "node_modules/@jimp/plugin-gaussian": { 214 | "version": "0.22.8", 215 | "resolved": "https://registry.npmjs.org/@jimp/plugin-gaussian/-/plugin-gaussian-0.22.8.tgz", 216 | "integrity": "sha512-E/f14aLzCS50QAM7K+InI9V61KVy/Zx52vy7Jjfo1h7qKhQHss3PYaydaH0N6qlXRNeXgh+4/32P9JfieLMcdw==", 217 | "dependencies": { 218 | "@jimp/utils": "^0.22.8" 219 | }, 220 | "peerDependencies": { 221 | "@jimp/custom": ">=0.3.5" 222 | } 223 | }, 224 | "node_modules/@jimp/plugin-invert": { 225 | "version": "0.22.8", 226 | "resolved": "https://registry.npmjs.org/@jimp/plugin-invert/-/plugin-invert-0.22.8.tgz", 227 | "integrity": "sha512-UauP39FF2cwbA5VU+Tz9VlNa9rtULPSHZb0Huwcjqjm9/G/xVN69VJ8+RKiFC4zM1/kYAUp/6IRwPa6qdKJpSw==", 228 | "dependencies": { 229 | "@jimp/utils": "^0.22.8" 230 | }, 231 | "peerDependencies": { 232 | "@jimp/custom": ">=0.3.5" 233 | } 234 | }, 235 | "node_modules/@jimp/plugin-mask": { 236 | "version": "0.22.8", 237 | "resolved": "https://registry.npmjs.org/@jimp/plugin-mask/-/plugin-mask-0.22.8.tgz", 238 | "integrity": "sha512-bhg5+3i8x1CmYj6cjvPBQZLwZEI3iK3gJWF25ZHF+12d3cqDuJngtr8oRQOQLlAgvKmrj9FXIiEPDczUI9cnWQ==", 239 | "dependencies": { 240 | "@jimp/utils": "^0.22.8" 241 | }, 242 | "peerDependencies": { 243 | "@jimp/custom": ">=0.3.5" 244 | } 245 | }, 246 | "node_modules/@jimp/plugin-normalize": { 247 | "version": "0.22.8", 248 | "resolved": "https://registry.npmjs.org/@jimp/plugin-normalize/-/plugin-normalize-0.22.8.tgz", 249 | "integrity": "sha512-Yg5nreAR1JYuSObu3ExlgaLxVeW6VvjVL5qFwiPFxSNlG8JIwL1Ir3K3ChSnnvymyZvJMHb6YKTYNfXKw5Da6g==", 250 | "dependencies": { 251 | "@jimp/utils": "^0.22.8" 252 | }, 253 | "peerDependencies": { 254 | "@jimp/custom": ">=0.3.5" 255 | } 256 | }, 257 | "node_modules/@jimp/plugin-print": { 258 | "version": "0.22.8", 259 | "resolved": "https://registry.npmjs.org/@jimp/plugin-print/-/plugin-print-0.22.8.tgz", 260 | "integrity": "sha512-86O5ejCDi543IYl0TykSmNWErzAjEYhiAxNQb2F7rFRT38WJYNVsvJ6QhxhDQHKxSmF5iwmqbk0jYk5Wp2Z1kw==", 261 | "dependencies": { 262 | "@jimp/utils": "^0.22.8", 263 | "load-bmfont": "^1.4.1" 264 | }, 265 | "peerDependencies": { 266 | "@jimp/custom": ">=0.3.5", 267 | "@jimp/plugin-blit": ">=0.3.5" 268 | } 269 | }, 270 | "node_modules/@jimp/plugin-resize": { 271 | "version": "0.22.8", 272 | "resolved": "https://registry.npmjs.org/@jimp/plugin-resize/-/plugin-resize-0.22.8.tgz", 273 | "integrity": "sha512-kg8ArQRPqv/iU3DWNXCa8kcVIhoq64Ze0aGCAeFLKlAq/59f5pzAci6m6vV4L/uOVdYmUa9/kYwIFY6RWKpfzQ==", 274 | "dependencies": { 275 | "@jimp/utils": "^0.22.8" 276 | }, 277 | "peerDependencies": { 278 | "@jimp/custom": ">=0.3.5" 279 | } 280 | }, 281 | "node_modules/@jimp/plugin-rotate": { 282 | "version": "0.22.8", 283 | "resolved": "https://registry.npmjs.org/@jimp/plugin-rotate/-/plugin-rotate-0.22.8.tgz", 284 | "integrity": "sha512-9a+VPZWMN/Cks76wf8LjM5RVA3ntP9+NAdsS1SZhhXel7U3Re/dWMouIEbo3QTt6K+igRo4txUCdZiw4ZucvkQ==", 285 | "dependencies": { 286 | "@jimp/utils": "^0.22.8" 287 | }, 288 | "peerDependencies": { 289 | "@jimp/custom": ">=0.3.5", 290 | "@jimp/plugin-blit": ">=0.3.5", 291 | "@jimp/plugin-crop": ">=0.3.5", 292 | "@jimp/plugin-resize": ">=0.3.5" 293 | } 294 | }, 295 | "node_modules/@jimp/plugin-scale": { 296 | "version": "0.22.8", 297 | "resolved": "https://registry.npmjs.org/@jimp/plugin-scale/-/plugin-scale-0.22.8.tgz", 298 | "integrity": "sha512-dQS4pG6DX6endu8zUpvBBOEtGC+ljDDDNw0scSXY71TxyQdNo5Ro0apfsppjmuAr8rNotRkfyxbITKkXQDRUDQ==", 299 | "dependencies": { 300 | "@jimp/utils": "^0.22.8" 301 | }, 302 | "peerDependencies": { 303 | "@jimp/custom": ">=0.3.5", 304 | "@jimp/plugin-resize": ">=0.3.5" 305 | } 306 | }, 307 | "node_modules/@jimp/plugin-shadow": { 308 | "version": "0.22.8", 309 | "resolved": "https://registry.npmjs.org/@jimp/plugin-shadow/-/plugin-shadow-0.22.8.tgz", 310 | "integrity": "sha512-HyAhr7OblTQh+BoKHQg4qbS9MweNlH77yfpBqUEyDtfyjI5r06+5chf1ZdLRIPEWv/BdCfdI/g81Wv69muCMwA==", 311 | "dependencies": { 312 | "@jimp/utils": "^0.22.8" 313 | }, 314 | "peerDependencies": { 315 | "@jimp/custom": ">=0.3.5", 316 | "@jimp/plugin-blur": ">=0.3.5", 317 | "@jimp/plugin-resize": ">=0.3.5" 318 | } 319 | }, 320 | "node_modules/@jimp/plugin-threshold": { 321 | "version": "0.22.8", 322 | "resolved": "https://registry.npmjs.org/@jimp/plugin-threshold/-/plugin-threshold-0.22.8.tgz", 323 | "integrity": "sha512-ZmkfH0PtjvF1UcKsjw0H7V6r+LC0yKzEfg76Jhs2nIqIgsxsSOVfHwS7z0/1IWnyXxSw36m+NjCAotNHRILGmA==", 324 | "dependencies": { 325 | "@jimp/utils": "^0.22.8" 326 | }, 327 | "peerDependencies": { 328 | "@jimp/custom": ">=0.3.5", 329 | "@jimp/plugin-color": ">=0.8.0", 330 | "@jimp/plugin-resize": ">=0.8.0" 331 | } 332 | }, 333 | "node_modules/@jimp/plugins": { 334 | "version": "0.22.8", 335 | "resolved": "https://registry.npmjs.org/@jimp/plugins/-/plugins-0.22.8.tgz", 336 | "integrity": "sha512-ieI2+kCpmIfjwVlT7B67ULCzxMizfj7LspJh9HnIZCDXQB9GBOZ9KImLYc75Krae0dP/3FR7FglLiSI7fkOHbw==", 337 | "dependencies": { 338 | "@jimp/plugin-blit": "^0.22.8", 339 | "@jimp/plugin-blur": "^0.22.8", 340 | "@jimp/plugin-circle": "^0.22.8", 341 | "@jimp/plugin-color": "^0.22.8", 342 | "@jimp/plugin-contain": "^0.22.8", 343 | "@jimp/plugin-cover": "^0.22.8", 344 | "@jimp/plugin-crop": "^0.22.8", 345 | "@jimp/plugin-displace": "^0.22.8", 346 | "@jimp/plugin-dither": "^0.22.8", 347 | "@jimp/plugin-fisheye": "^0.22.8", 348 | "@jimp/plugin-flip": "^0.22.8", 349 | "@jimp/plugin-gaussian": "^0.22.8", 350 | "@jimp/plugin-invert": "^0.22.8", 351 | "@jimp/plugin-mask": "^0.22.8", 352 | "@jimp/plugin-normalize": "^0.22.8", 353 | "@jimp/plugin-print": "^0.22.8", 354 | "@jimp/plugin-resize": "^0.22.8", 355 | "@jimp/plugin-rotate": "^0.22.8", 356 | "@jimp/plugin-scale": "^0.22.8", 357 | "@jimp/plugin-shadow": "^0.22.8", 358 | "@jimp/plugin-threshold": "^0.22.8", 359 | "timm": "^1.6.1" 360 | }, 361 | "peerDependencies": { 362 | "@jimp/custom": ">=0.3.5" 363 | } 364 | }, 365 | "node_modules/@jimp/png": { 366 | "version": "0.22.8", 367 | "resolved": "https://registry.npmjs.org/@jimp/png/-/png-0.22.8.tgz", 368 | "integrity": "sha512-XOj11kcCr8zKg24QSwlRfH9k4hbV6rkMGUVxMS3puRzzB0FBSQy42NBYEfYf2XlY2QJSAByPl4AYerOtKb805w==", 369 | "dependencies": { 370 | "@jimp/utils": "^0.22.8", 371 | "pngjs": "^6.0.0" 372 | }, 373 | "peerDependencies": { 374 | "@jimp/custom": ">=0.3.5" 375 | } 376 | }, 377 | "node_modules/@jimp/tiff": { 378 | "version": "0.22.8", 379 | "resolved": "https://registry.npmjs.org/@jimp/tiff/-/tiff-0.22.8.tgz", 380 | "integrity": "sha512-K0hYUVW5MLgwq3jiHVHa6LvP05J1rXOlRCC+5dMTUnAXVwi45+MKsqA/8lzzwhHYJ65CNhZwy6D3+ZNzM9SIBQ==", 381 | "dependencies": { 382 | "utif2": "^4.0.1" 383 | }, 384 | "peerDependencies": { 385 | "@jimp/custom": ">=0.3.5" 386 | } 387 | }, 388 | "node_modules/@jimp/types": { 389 | "version": "0.22.8", 390 | "resolved": "https://registry.npmjs.org/@jimp/types/-/types-0.22.8.tgz", 391 | "integrity": "sha512-9+xc+mzuYwu0i+6dsnhXiUgfcS+Ktqn5q2jczoKyyBT0cOKgsk+57EIeFLgpTfVGRKRR0y/UIdHByeCzGguF3A==", 392 | "dependencies": { 393 | "@jimp/bmp": "^0.22.8", 394 | "@jimp/gif": "^0.22.8", 395 | "@jimp/jpeg": "^0.22.8", 396 | "@jimp/png": "^0.22.8", 397 | "@jimp/tiff": "^0.22.8", 398 | "timm": "^1.6.1" 399 | }, 400 | "peerDependencies": { 401 | "@jimp/custom": ">=0.3.5" 402 | } 403 | }, 404 | "node_modules/@jimp/utils": { 405 | "version": "0.22.8", 406 | "resolved": "https://registry.npmjs.org/@jimp/utils/-/utils-0.22.8.tgz", 407 | "integrity": "sha512-AaqjfqDeLzSFzrbGRKHMXg/ntiWKvoG9tpVgWzgOx5/gPWj/IyGfztojLTTvY8HqZCr25z8z91u2lAQD2v46Jw==", 408 | "dependencies": { 409 | "regenerator-runtime": "^0.13.3" 410 | } 411 | }, 412 | "node_modules/@tokenizer/token": { 413 | "version": "0.3.0", 414 | "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", 415 | "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==" 416 | }, 417 | "node_modules/@types/jimp": { 418 | "version": "0.2.28", 419 | "resolved": "https://registry.npmjs.org/@types/jimp/-/jimp-0.2.28.tgz", 420 | "integrity": "sha512-nLIVbImtcaEf90y2XQsMzfgWK5EZxfDg6EVWobrkFTFJiLqmx/yU5Jh+LYUN94ztzXX1GwQLFYHaEi8tfMeZzw==", 421 | "deprecated": "This is a stub types definition for jimp (https://github.com/oliver-moran/jimp#readme). jimp provides its own type definitions, so you don't need @types/jimp installed!", 422 | "dev": true, 423 | "dependencies": { 424 | "jimp": "*" 425 | } 426 | }, 427 | "node_modules/@types/node": { 428 | "version": "20.3.0", 429 | "resolved": "https://registry.npmjs.org/@types/node/-/node-20.3.0.tgz", 430 | "integrity": "sha512-cumHmIAf6On83X7yP+LrsEyUOf/YlociZelmpRYaGFydoaPdxdt80MAbu6vWerQT2COCp2nPvHdsbD7tHn/YlQ==" 431 | }, 432 | "node_modules/any-base": { 433 | "version": "1.1.0", 434 | "resolved": "https://registry.npmjs.org/any-base/-/any-base-1.1.0.tgz", 435 | "integrity": "sha512-uMgjozySS8adZZYePpaWs8cxB9/kdzmpX6SgJZ+wbz1K5eYk5QMYDVJaZKhxyIHUdnnJkfR7SVgStgH7LkGUyg==" 436 | }, 437 | "node_modules/base64-js": { 438 | "version": "1.5.1", 439 | "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", 440 | "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", 441 | "funding": [ 442 | { 443 | "type": "github", 444 | "url": "https://github.com/sponsors/feross" 445 | }, 446 | { 447 | "type": "patreon", 448 | "url": "https://www.patreon.com/feross" 449 | }, 450 | { 451 | "type": "consulting", 452 | "url": "https://feross.org/support" 453 | } 454 | ] 455 | }, 456 | "node_modules/bmp-js": { 457 | "version": "0.1.0", 458 | "resolved": "https://registry.npmjs.org/bmp-js/-/bmp-js-0.1.0.tgz", 459 | "integrity": "sha512-vHdS19CnY3hwiNdkaqk93DvjVLfbEcI8mys4UjuWrlX1haDmroo8o4xCzh4wD6DGV6HxRCyauwhHRqMTfERtjw==" 460 | }, 461 | "node_modules/buffer": { 462 | "version": "5.7.1", 463 | "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", 464 | "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", 465 | "funding": [ 466 | { 467 | "type": "github", 468 | "url": "https://github.com/sponsors/feross" 469 | }, 470 | { 471 | "type": "patreon", 472 | "url": "https://www.patreon.com/feross" 473 | }, 474 | { 475 | "type": "consulting", 476 | "url": "https://feross.org/support" 477 | } 478 | ], 479 | "dependencies": { 480 | "base64-js": "^1.3.1", 481 | "ieee754": "^1.1.13" 482 | } 483 | }, 484 | "node_modules/buffer-equal": { 485 | "version": "0.0.1", 486 | "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-0.0.1.tgz", 487 | "integrity": "sha512-RgSV6InVQ9ODPdLWJ5UAqBqJBOg370Nz6ZQtRzpt6nUjc8v0St97uJ4PYC6NztqIScrAXafKM3mZPMygSe1ggA==", 488 | "engines": { 489 | "node": ">=0.4.0" 490 | } 491 | }, 492 | "node_modules/chalk": { 493 | "version": "5.2.0", 494 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.2.0.tgz", 495 | "integrity": "sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==", 496 | "engines": { 497 | "node": "^12.17.0 || ^14.13 || >=16.0.0" 498 | }, 499 | "funding": { 500 | "url": "https://github.com/chalk/chalk?sponsor=1" 501 | } 502 | }, 503 | "node_modules/child_process": { 504 | "version": "1.0.2", 505 | "resolved": "https://registry.npmjs.org/child_process/-/child_process-1.0.2.tgz", 506 | "integrity": "sha512-Wmza/JzL0SiWz7kl6MhIKT5ceIlnFPJX+lwUGj7Clhy5MMldsSoJR0+uvRzOS5Kv45Mq7t1PoE8TsOA9bzvb6g==" 507 | }, 508 | "node_modules/dom-walk": { 509 | "version": "0.1.2", 510 | "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz", 511 | "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==" 512 | }, 513 | "node_modules/exif-parser": { 514 | "version": "0.1.12", 515 | "resolved": "https://registry.npmjs.org/exif-parser/-/exif-parser-0.1.12.tgz", 516 | "integrity": "sha512-c2bQfLNbMzLPmzQuOr8fy0csy84WmwnER81W88DzTp9CYNPJ6yzOj2EZAh9pywYpqHnshVLHQJ8WzldAyfY+Iw==" 517 | }, 518 | "node_modules/file-type": { 519 | "version": "16.5.4", 520 | "resolved": "https://registry.npmjs.org/file-type/-/file-type-16.5.4.tgz", 521 | "integrity": "sha512-/yFHK0aGjFEgDJjEKP0pWCplsPFPhwyfwevf/pVxiN0tmE4L9LmwWxWukdJSHdoCli4VgQLehjJtwQBnqmsKcw==", 522 | "dependencies": { 523 | "readable-web-to-node-stream": "^3.0.0", 524 | "strtok3": "^6.2.4", 525 | "token-types": "^4.1.1" 526 | }, 527 | "engines": { 528 | "node": ">=10" 529 | }, 530 | "funding": { 531 | "url": "https://github.com/sindresorhus/file-type?sponsor=1" 532 | } 533 | }, 534 | "node_modules/gifwrap": { 535 | "version": "0.9.4", 536 | "resolved": "https://registry.npmjs.org/gifwrap/-/gifwrap-0.9.4.tgz", 537 | "integrity": "sha512-MDMwbhASQuVeD4JKd1fKgNgCRL3fGqMM4WaqpNhWO0JiMOAjbQdumbs4BbBZEy9/M00EHEjKN3HieVhCUlwjeQ==", 538 | "dependencies": { 539 | "image-q": "^4.0.0", 540 | "omggif": "^1.0.10" 541 | } 542 | }, 543 | "node_modules/global": { 544 | "version": "4.4.0", 545 | "resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz", 546 | "integrity": "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==", 547 | "dependencies": { 548 | "min-document": "^2.19.0", 549 | "process": "^0.11.10" 550 | } 551 | }, 552 | "node_modules/ieee754": { 553 | "version": "1.2.1", 554 | "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", 555 | "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", 556 | "funding": [ 557 | { 558 | "type": "github", 559 | "url": "https://github.com/sponsors/feross" 560 | }, 561 | { 562 | "type": "patreon", 563 | "url": "https://www.patreon.com/feross" 564 | }, 565 | { 566 | "type": "consulting", 567 | "url": "https://feross.org/support" 568 | } 569 | ] 570 | }, 571 | "node_modules/image-q": { 572 | "version": "4.0.0", 573 | "resolved": "https://registry.npmjs.org/image-q/-/image-q-4.0.0.tgz", 574 | "integrity": "sha512-PfJGVgIfKQJuq3s0tTDOKtztksibuUEbJQIYT3by6wctQo+Rdlh7ef4evJ5NCdxY4CfMbvFkocEwbl4BF8RlJw==", 575 | "dependencies": { 576 | "@types/node": "16.9.1" 577 | } 578 | }, 579 | "node_modules/image-q/node_modules/@types/node": { 580 | "version": "16.9.1", 581 | "resolved": "https://registry.npmjs.org/@types/node/-/node-16.9.1.tgz", 582 | "integrity": "sha512-QpLcX9ZSsq3YYUUnD3nFDY8H7wctAhQj/TFKL8Ya8v5fMm3CFXxo8zStsLAl780ltoYoo1WvKUVGBQK+1ifr7g==" 583 | }, 584 | "node_modules/inherits": { 585 | "version": "2.0.4", 586 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 587 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" 588 | }, 589 | "node_modules/is-function": { 590 | "version": "1.0.2", 591 | "resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.2.tgz", 592 | "integrity": "sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ==" 593 | }, 594 | "node_modules/isomorphic-fetch": { 595 | "version": "3.0.0", 596 | "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-3.0.0.tgz", 597 | "integrity": "sha512-qvUtwJ3j6qwsF3jLxkZ72qCgjMysPzDfeV240JHiGZsANBYd+EEuu35v7dfrJ9Up0Ak07D7GGSkGhCHTqg/5wA==", 598 | "dependencies": { 599 | "node-fetch": "^2.6.1", 600 | "whatwg-fetch": "^3.4.1" 601 | } 602 | }, 603 | "node_modules/jimp": { 604 | "version": "0.22.8", 605 | "resolved": "https://registry.npmjs.org/jimp/-/jimp-0.22.8.tgz", 606 | "integrity": "sha512-pBbrooJMX7795sDcxx1XpwNZC8B/ITyDV+JK2/1qNbQl/1UWqWeh5Dq7qQpMZl5jLdcFDv5IVTM+OhpafSqSFA==", 607 | "dependencies": { 608 | "@jimp/custom": "^0.22.8", 609 | "@jimp/plugins": "^0.22.8", 610 | "@jimp/types": "^0.22.8", 611 | "regenerator-runtime": "^0.13.3" 612 | } 613 | }, 614 | "node_modules/jpeg-js": { 615 | "version": "0.4.4", 616 | "resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.4.4.tgz", 617 | "integrity": "sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg==" 618 | }, 619 | "node_modules/load-bmfont": { 620 | "version": "1.4.1", 621 | "resolved": "https://registry.npmjs.org/load-bmfont/-/load-bmfont-1.4.1.tgz", 622 | "integrity": "sha512-8UyQoYmdRDy81Brz6aLAUhfZLwr5zV0L3taTQ4hju7m6biuwiWiJXjPhBJxbUQJA8PrkvJ/7Enqmwk2sM14soA==", 623 | "dependencies": { 624 | "buffer-equal": "0.0.1", 625 | "mime": "^1.3.4", 626 | "parse-bmfont-ascii": "^1.0.3", 627 | "parse-bmfont-binary": "^1.0.5", 628 | "parse-bmfont-xml": "^1.1.4", 629 | "phin": "^2.9.1", 630 | "xhr": "^2.0.1", 631 | "xtend": "^4.0.0" 632 | } 633 | }, 634 | "node_modules/mime": { 635 | "version": "1.6.0", 636 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", 637 | "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", 638 | "bin": { 639 | "mime": "cli.js" 640 | }, 641 | "engines": { 642 | "node": ">=4" 643 | } 644 | }, 645 | "node_modules/min-document": { 646 | "version": "2.19.0", 647 | "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz", 648 | "integrity": "sha512-9Wy1B3m3f66bPPmU5hdA4DR4PB2OfDU/+GS3yAB7IQozE3tqXaVv2zOjgla7MEGSRv95+ILmOuvhLkOK6wJtCQ==", 649 | "dependencies": { 650 | "dom-walk": "^0.1.0" 651 | } 652 | }, 653 | "node_modules/mkdirp": { 654 | "version": "2.1.6", 655 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-2.1.6.tgz", 656 | "integrity": "sha512-+hEnITedc8LAtIP9u3HJDFIdcLV2vXP33sqLLIzkv1Db1zO/1OxbvYf0Y1OC/S/Qo5dxHXepofhmxL02PsKe+A==", 657 | "bin": { 658 | "mkdirp": "dist/cjs/src/bin.js" 659 | }, 660 | "engines": { 661 | "node": ">=10" 662 | }, 663 | "funding": { 664 | "url": "https://github.com/sponsors/isaacs" 665 | } 666 | }, 667 | "node_modules/node-fetch": { 668 | "version": "2.6.11", 669 | "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.11.tgz", 670 | "integrity": "sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w==", 671 | "dependencies": { 672 | "whatwg-url": "^5.0.0" 673 | }, 674 | "engines": { 675 | "node": "4.x || >=6.0.0" 676 | }, 677 | "peerDependencies": { 678 | "encoding": "^0.1.0" 679 | }, 680 | "peerDependenciesMeta": { 681 | "encoding": { 682 | "optional": true 683 | } 684 | } 685 | }, 686 | "node_modules/omggif": { 687 | "version": "1.0.10", 688 | "resolved": "https://registry.npmjs.org/omggif/-/omggif-1.0.10.tgz", 689 | "integrity": "sha512-LMJTtvgc/nugXj0Vcrrs68Mn2D1r0zf630VNtqtpI1FEO7e+O9FP4gqs9AcnBaSEeoHIPm28u6qgPR0oyEpGSw==" 690 | }, 691 | "node_modules/pako": { 692 | "version": "1.0.11", 693 | "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", 694 | "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" 695 | }, 696 | "node_modules/parse-bmfont-ascii": { 697 | "version": "1.0.6", 698 | "resolved": "https://registry.npmjs.org/parse-bmfont-ascii/-/parse-bmfont-ascii-1.0.6.tgz", 699 | "integrity": "sha512-U4RrVsUFCleIOBsIGYOMKjn9PavsGOXxbvYGtMOEfnId0SVNsgehXh1DxUdVPLoxd5mvcEtvmKs2Mmf0Mpa1ZA==" 700 | }, 701 | "node_modules/parse-bmfont-binary": { 702 | "version": "1.0.6", 703 | "resolved": "https://registry.npmjs.org/parse-bmfont-binary/-/parse-bmfont-binary-1.0.6.tgz", 704 | "integrity": "sha512-GxmsRea0wdGdYthjuUeWTMWPqm2+FAd4GI8vCvhgJsFnoGhTrLhXDDupwTo7rXVAgaLIGoVHDZS9p/5XbSqeWA==" 705 | }, 706 | "node_modules/parse-bmfont-xml": { 707 | "version": "1.1.4", 708 | "resolved": "https://registry.npmjs.org/parse-bmfont-xml/-/parse-bmfont-xml-1.1.4.tgz", 709 | "integrity": "sha512-bjnliEOmGv3y1aMEfREMBJ9tfL3WR0i0CKPj61DnSLaoxWR3nLrsQrEbCId/8rF4NyRF0cCqisSVXyQYWM+mCQ==", 710 | "dependencies": { 711 | "xml-parse-from-string": "^1.0.0", 712 | "xml2js": "^0.4.5" 713 | } 714 | }, 715 | "node_modules/parse-headers": { 716 | "version": "2.0.5", 717 | "resolved": "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.5.tgz", 718 | "integrity": "sha512-ft3iAoLOB/MlwbNXgzy43SWGP6sQki2jQvAyBg/zDFAgr9bfNWZIUj42Kw2eJIl8kEi4PbgE6U1Zau/HwI75HA==" 719 | }, 720 | "node_modules/peek-readable": { 721 | "version": "4.1.0", 722 | "resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-4.1.0.tgz", 723 | "integrity": "sha512-ZI3LnwUv5nOGbQzD9c2iDG6toheuXSZP5esSHBjopsXH4dg19soufvpUGA3uohi5anFtGb2lhAVdHzH6R/Evvg==", 724 | "engines": { 725 | "node": ">=8" 726 | }, 727 | "funding": { 728 | "type": "github", 729 | "url": "https://github.com/sponsors/Borewit" 730 | } 731 | }, 732 | "node_modules/phin": { 733 | "version": "2.9.3", 734 | "resolved": "https://registry.npmjs.org/phin/-/phin-2.9.3.tgz", 735 | "integrity": "sha512-CzFr90qM24ju5f88quFC/6qohjC144rehe5n6DH900lgXmUe86+xCKc10ev56gRKC4/BkHUoG4uSiQgBiIXwDA==" 736 | }, 737 | "node_modules/pixelmatch": { 738 | "version": "4.0.2", 739 | "resolved": "https://registry.npmjs.org/pixelmatch/-/pixelmatch-4.0.2.tgz", 740 | "integrity": "sha512-J8B6xqiO37sU/gkcMglv6h5Jbd9xNER7aHzpfRdNmV4IbQBzBpe4l9XmbG+xPF/znacgu2jfEw+wHffaq/YkXA==", 741 | "dependencies": { 742 | "pngjs": "^3.0.0" 743 | }, 744 | "bin": { 745 | "pixelmatch": "bin/pixelmatch" 746 | } 747 | }, 748 | "node_modules/pixelmatch/node_modules/pngjs": { 749 | "version": "3.4.0", 750 | "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-3.4.0.tgz", 751 | "integrity": "sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==", 752 | "engines": { 753 | "node": ">=4.0.0" 754 | } 755 | }, 756 | "node_modules/pngjs": { 757 | "version": "6.0.0", 758 | "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-6.0.0.tgz", 759 | "integrity": "sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg==", 760 | "engines": { 761 | "node": ">=12.13.0" 762 | } 763 | }, 764 | "node_modules/process": { 765 | "version": "0.11.10", 766 | "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", 767 | "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", 768 | "engines": { 769 | "node": ">= 0.6.0" 770 | } 771 | }, 772 | "node_modules/readable-stream": { 773 | "version": "3.6.2", 774 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", 775 | "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", 776 | "dependencies": { 777 | "inherits": "^2.0.3", 778 | "string_decoder": "^1.1.1", 779 | "util-deprecate": "^1.0.1" 780 | }, 781 | "engines": { 782 | "node": ">= 6" 783 | } 784 | }, 785 | "node_modules/readable-web-to-node-stream": { 786 | "version": "3.0.2", 787 | "resolved": "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz", 788 | "integrity": "sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw==", 789 | "dependencies": { 790 | "readable-stream": "^3.6.0" 791 | }, 792 | "engines": { 793 | "node": ">=8" 794 | }, 795 | "funding": { 796 | "type": "github", 797 | "url": "https://github.com/sponsors/Borewit" 798 | } 799 | }, 800 | "node_modules/readline": { 801 | "version": "1.3.0", 802 | "resolved": "https://registry.npmjs.org/readline/-/readline-1.3.0.tgz", 803 | "integrity": "sha512-k2d6ACCkiNYz222Fs/iNze30rRJ1iIicW7JuX/7/cozvih6YCkFZH+J6mAFDVgv0dRBaAyr4jDqC95R2y4IADg==" 804 | }, 805 | "node_modules/regenerator-runtime": { 806 | "version": "0.13.11", 807 | "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", 808 | "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" 809 | }, 810 | "node_modules/safe-buffer": { 811 | "version": "5.2.1", 812 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 813 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", 814 | "funding": [ 815 | { 816 | "type": "github", 817 | "url": "https://github.com/sponsors/feross" 818 | }, 819 | { 820 | "type": "patreon", 821 | "url": "https://www.patreon.com/feross" 822 | }, 823 | { 824 | "type": "consulting", 825 | "url": "https://feross.org/support" 826 | } 827 | ] 828 | }, 829 | "node_modules/sax": { 830 | "version": "1.2.4", 831 | "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", 832 | "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" 833 | }, 834 | "node_modules/string_decoder": { 835 | "version": "1.3.0", 836 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", 837 | "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", 838 | "dependencies": { 839 | "safe-buffer": "~5.2.0" 840 | } 841 | }, 842 | "node_modules/strtok3": { 843 | "version": "6.3.0", 844 | "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-6.3.0.tgz", 845 | "integrity": "sha512-fZtbhtvI9I48xDSywd/somNqgUHl2L2cstmXCCif0itOf96jeW18MBSyrLuNicYQVkvpOxkZtkzujiTJ9LW5Jw==", 846 | "dependencies": { 847 | "@tokenizer/token": "^0.3.0", 848 | "peek-readable": "^4.1.0" 849 | }, 850 | "engines": { 851 | "node": ">=10" 852 | }, 853 | "funding": { 854 | "type": "github", 855 | "url": "https://github.com/sponsors/Borewit" 856 | } 857 | }, 858 | "node_modules/timm": { 859 | "version": "1.7.1", 860 | "resolved": "https://registry.npmjs.org/timm/-/timm-1.7.1.tgz", 861 | "integrity": "sha512-IjZc9KIotudix8bMaBW6QvMuq64BrJWFs1+4V0lXwWGQZwH+LnX87doAYhem4caOEusRP9/g6jVDQmZ8XOk1nw==" 862 | }, 863 | "node_modules/tinycolor2": { 864 | "version": "1.6.0", 865 | "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.6.0.tgz", 866 | "integrity": "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==" 867 | }, 868 | "node_modules/token-types": { 869 | "version": "4.2.1", 870 | "resolved": "https://registry.npmjs.org/token-types/-/token-types-4.2.1.tgz", 871 | "integrity": "sha512-6udB24Q737UD/SDsKAHI9FCRP7Bqc9D/MQUV02ORQg5iskjtLJlZJNdN4kKtcdtwCeWIwIHDGaUsTsCCAa8sFQ==", 872 | "dependencies": { 873 | "@tokenizer/token": "^0.3.0", 874 | "ieee754": "^1.2.1" 875 | }, 876 | "engines": { 877 | "node": ">=10" 878 | }, 879 | "funding": { 880 | "type": "github", 881 | "url": "https://github.com/sponsors/Borewit" 882 | } 883 | }, 884 | "node_modules/tr46": { 885 | "version": "0.0.3", 886 | "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", 887 | "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" 888 | }, 889 | "node_modules/typescript": { 890 | "version": "5.1.3", 891 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.3.tgz", 892 | "integrity": "sha512-XH627E9vkeqhlZFQuL+UsyAXEnibT0kWR2FWONlr4sTjvxyJYnyefgrkyECLzM5NenmKzRAy2rR/OlYLA1HkZw==", 893 | "bin": { 894 | "tsc": "bin/tsc", 895 | "tsserver": "bin/tsserver" 896 | }, 897 | "engines": { 898 | "node": ">=14.17" 899 | } 900 | }, 901 | "node_modules/utif2": { 902 | "version": "4.1.0", 903 | "resolved": "https://registry.npmjs.org/utif2/-/utif2-4.1.0.tgz", 904 | "integrity": "sha512-+oknB9FHrJ7oW7A2WZYajOcv4FcDR4CfoGB0dPNfxbi4GO05RRnFmt5oa23+9w32EanrYcSJWspUiJkLMs+37w==", 905 | "dependencies": { 906 | "pako": "^1.0.11" 907 | } 908 | }, 909 | "node_modules/util-deprecate": { 910 | "version": "1.0.2", 911 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 912 | "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" 913 | }, 914 | "node_modules/webidl-conversions": { 915 | "version": "3.0.1", 916 | "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", 917 | "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" 918 | }, 919 | "node_modules/whatwg-fetch": { 920 | "version": "3.6.2", 921 | "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz", 922 | "integrity": "sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA==" 923 | }, 924 | "node_modules/whatwg-url": { 925 | "version": "5.0.0", 926 | "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", 927 | "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", 928 | "dependencies": { 929 | "tr46": "~0.0.3", 930 | "webidl-conversions": "^3.0.0" 931 | } 932 | }, 933 | "node_modules/xhr": { 934 | "version": "2.6.0", 935 | "resolved": "https://registry.npmjs.org/xhr/-/xhr-2.6.0.tgz", 936 | "integrity": "sha512-/eCGLb5rxjx5e3mF1A7s+pLlR6CGyqWN91fv1JgER5mVWg1MZmlhBvy9kjcsOdRk8RrIujotWyJamfyrp+WIcA==", 937 | "dependencies": { 938 | "global": "~4.4.0", 939 | "is-function": "^1.0.1", 940 | "parse-headers": "^2.0.0", 941 | "xtend": "^4.0.0" 942 | } 943 | }, 944 | "node_modules/xml-parse-from-string": { 945 | "version": "1.0.1", 946 | "resolved": "https://registry.npmjs.org/xml-parse-from-string/-/xml-parse-from-string-1.0.1.tgz", 947 | "integrity": "sha512-ErcKwJTF54uRzzNMXq2X5sMIy88zJvfN2DmdoQvy7PAFJ+tPRU6ydWuOKNMyfmOjdyBQTFREi60s0Y0SyI0G0g==" 948 | }, 949 | "node_modules/xml2js": { 950 | "version": "0.4.23", 951 | "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", 952 | "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", 953 | "dependencies": { 954 | "sax": ">=0.6.0", 955 | "xmlbuilder": "~11.0.0" 956 | }, 957 | "engines": { 958 | "node": ">=4.0.0" 959 | } 960 | }, 961 | "node_modules/xmlbuilder": { 962 | "version": "11.0.1", 963 | "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", 964 | "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", 965 | "engines": { 966 | "node": ">=4.0" 967 | } 968 | }, 969 | "node_modules/xtend": { 970 | "version": "4.0.2", 971 | "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", 972 | "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", 973 | "engines": { 974 | "node": ">=0.4" 975 | } 976 | } 977 | } 978 | } 979 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nodecli-gui", 3 | "version": "1.0.12", 4 | "description": "Try using cli like gui.", 5 | "main": "./dist/index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "ice1", 11 | "license": "MIT", 12 | "dependencies": { 13 | "@types/node": "^20.3.0", 14 | "chalk": "^5.2.0", 15 | "child_process": "^1.0.2", 16 | "jimp": "^0.22.8", 17 | "readline": "^1.3.0", 18 | "typescript": "^5.1.3" 19 | }, 20 | "type": "module", 21 | "devDependencies": { 22 | "@types/jimp": "^0.2.28" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export { CLIGlobal } from './lib/CLIGlobal.js'; 2 | 3 | export { CLIApplication } from './lib/CLIApplication.js'; 4 | 5 | export { CLILabel } from './lib/CLIWidgets/CLILabel.js'; 6 | export { CLIButton } from './lib/CLIWidgets/CLIButton.js'; 7 | export { CLICheckBox } from './lib/CLIWidgets/CLICheckBox.js'; 8 | export { CLIRadioButton } from './lib/CLIWidgets/CLIRadioButton.js'; 9 | export { CLIImage } from './lib/CLIWidgets/CLIImage.js'; 10 | // export { CLIComboBox } from './lib/CLIWidgets/CLIComboBox.js'; -------------------------------------------------------------------------------- /src/lib/CLIApplication.ts: -------------------------------------------------------------------------------- 1 | import chalk from 'chalk'; 2 | import { exec } from 'child_process'; 3 | import { readFileSync, writeFileSync } from 'fs'; 4 | 5 | import { CLIGlobal } from './CLIGlobal.js'; 6 | 7 | interface IComponent { 8 | type: string; 9 | text: string; 10 | style: object; 11 | 12 | x: number; 13 | y: number; 14 | } 15 | 16 | interface IAgent { 17 | x: number; 18 | } 19 | 20 | interface IObj { 21 | id?: string; 22 | name?: string; 23 | } 24 | 25 | /** 26 | * CLI Application 27 | */ 28 | export class CLIApplication extends CLIGlobal { 29 | components: any[]; 30 | agent: IAgent; 31 | 32 | public constructor() { 33 | super(); 34 | 35 | this.components = []; 36 | this.agent = { 37 | x: 0 38 | }; 39 | } 40 | 41 | public find(obj: IObj) { 42 | let result: number; 43 | 44 | this.components.forEach((component, idx) => { 45 | if (obj?.name) { 46 | if (component.name === obj.name) result = idx; 47 | } else if (obj?.id) { 48 | if (component.id === obj.id) result = idx; 49 | } 50 | }); 51 | 52 | return result; 53 | } 54 | 55 | public remove(obj: IObj) { 56 | this.components.splice(this.find(obj), 1); 57 | } 58 | 59 | public modifyText(obj: IObj, { text }) { 60 | this.components[this.find(obj)].text = text; 61 | } 62 | 63 | public selectedItems(type: string = `checkbox`, { name } = { name: undefined }) { 64 | let result: any[] = []; 65 | 66 | this.components.forEach((component, idx) => { 67 | if (type === `checkbox`) { 68 | if (component.type === `checkbox` && component.toggleState) { 69 | result = [...result, component]; 70 | } 71 | } else if (type === `radiobutton`) { 72 | if (component.type === `radiobutton` && component.toggleState && component.name === name) { 73 | result = [...result, component]; 74 | } 75 | } 76 | }); 77 | 78 | return result; 79 | } 80 | 81 | public addComponent(component: IComponent, { x = 0, y = 0 }) { 82 | component.x = x; 83 | component.y = y; 84 | 85 | this.components = [...this.components, component]; 86 | } 87 | 88 | public show(time: number = 100) { 89 | process.stdin.setRawMode(true); 90 | process.stdin.setEncoding(`utf-8`); 91 | 92 | process.stdin.on(`data`, (key: string) => { 93 | if (key === `\u0003`) { 94 | console.clear(); 95 | process.stdout.write(`\x1B[?25h`); 96 | process.exit(); 97 | } 98 | 99 | if (key === `\u001b[D`) this.agent.x -= 1; 100 | if (key === `\u001B[C`) this.agent.x += 1; 101 | 102 | if (key === `\r` || key === `\n`) { 103 | this.components.forEach(component => { 104 | if (component?.type === `combobox` && this.find({ name: component.id }) === undefined) { 105 | component.items.forEach(item => { 106 | this.addComponent(item, { x: item.x, y: item.y }); 107 | }); 108 | } 109 | }); 110 | 111 | this.components.forEach((component, idx) => { 112 | if (this.agent.x === idx) { 113 | if (component?.selectEvent) { 114 | component.selectEvent(); 115 | 116 | if (component?.type === `checkbox`) { 117 | component.toggleState = !component.toggleState; 118 | } else if (component?.type === `radiobutton`) { 119 | this.selectedItems(`radiobutton`, { name: component.name }).forEach(item => { 120 | item.toggleState = false; 121 | }); 122 | 123 | component.toggleState = true; 124 | } else if (component?.type === `combobox`) { 125 | component.toggleState = !component.toggleState; 126 | } 127 | } 128 | } 129 | }); 130 | } 131 | 132 | if (this.agent.x === -1) this.agent.x = 0; 133 | if (this.agent.x === this.components.length) this.agent.x = this.components.length - 1; 134 | }); 135 | 136 | process.stdout.write(`\x1B[?25l`); 137 | 138 | setInterval(() => { 139 | console.clear(); 140 | 141 | this.components.forEach((component, idx) => { 142 | this.moveCursor({ x: component.x, y: component.y }); 143 | 144 | if (this.agent.x === idx && (component?.pickEvent || component?.selectEvent || component?.changeEvent)) { 145 | if ([`checkbox`, `radiobutton`].includes(component.type) && component?.toggleState === true) { 146 | console.log(`${component.beforeText}${chalk.italic.bold.overline.underline(component.text)}`); 147 | } else if (component?.type === `combobox` && component?.toggleState === true) { 148 | console.log(chalk.italic.bold.overline.underline(component.text)); 149 | } else { 150 | console.log(chalk.italic.bold.overline.underline(component.text)); 151 | } 152 | 153 | if (component?.pickEvent) component.pickEvent(); 154 | } else { 155 | if ([`checkbox`, `radiobutton`].includes(component.type) && component?.toggleState === true) { 156 | console.log(`${component.beforeText}${component.text}`); 157 | } else { 158 | console.log(component.text); 159 | } 160 | } 161 | }); 162 | }, time); 163 | } 164 | 165 | public setWindowTitle(title: string) { 166 | const config = JSON.parse(readFileSync(`./pkg-config.json`, `utf-8`)); 167 | config.win.title = title.trim(); 168 | 169 | writeFileSync(`./pkg-config.json`, JSON.stringify(config, null, 4)); 170 | } 171 | 172 | public setWindowIcon(path: string) { 173 | const config = JSON.parse(readFileSync(`./pkg-config.json`, `utf-8`)); 174 | config.icon = path.trim(); 175 | 176 | writeFileSync(`./pkg-config.json`, JSON.stringify(config, null, 4)); 177 | } 178 | 179 | public compile() { 180 | exec(`pkg . -c pkg-config.json`, { cwd: `./` }); 181 | } 182 | } -------------------------------------------------------------------------------- /src/lib/CLIGlobal.ts: -------------------------------------------------------------------------------- 1 | import chalk from 'chalk'; 2 | import { moveCursor } from 'readline'; 3 | 4 | interface IMoveCursor { 5 | x: number; 6 | y: number; 7 | } 8 | 9 | interface IThrowError { 10 | code: string; 11 | message: string; 12 | } 13 | 14 | /** 15 | * CLI Global 16 | */ 17 | export class CLIGlobal { 18 | public constructor() {} 19 | 20 | public moveCursor({ x, y }: IMoveCursor) { 21 | moveCursor(process.stdout, x, y); 22 | } 23 | 24 | public throwError({ code, message }: IThrowError) { 25 | throw new Error(`(code: ${code}) ${chalk.redBright.underline(message)}`); 26 | } 27 | 28 | public generateId() { 29 | return Math.random().toString(36).substring(2) + Math.random().toString(36).substring(2); 30 | } 31 | } -------------------------------------------------------------------------------- /src/lib/CLIWidgets/CLIButton.ts: -------------------------------------------------------------------------------- 1 | import { CLIGlobal } from '../CLIGlobal.js'; 2 | 3 | /** 4 | * CLI Button 5 | */ 6 | export class CLIButton extends CLIGlobal { 7 | id: string; 8 | 9 | labelText: string; 10 | 11 | pickEvent: Function; 12 | selectEvent: Function; 13 | 14 | public constructor({ text }) { 15 | super(); 16 | 17 | this.labelText = text; 18 | this.id = this.generateId(); 19 | } 20 | 21 | /** 22 | * @param {'pick' | 'select'} type 23 | */ 24 | public on(type: string, event: Function = () => {}) { 25 | if (type === `pick`) this.pickEvent = event; 26 | if (type === `select`) this.selectEvent = event; 27 | } 28 | 29 | public return() { 30 | return { 31 | type: `button`, 32 | 33 | id: this.id, 34 | 35 | text: this.labelText, 36 | 37 | pickEvent: this.pickEvent, 38 | selectEvent: this.selectEvent 39 | }; 40 | } 41 | } -------------------------------------------------------------------------------- /src/lib/CLIWidgets/CLICheckBox.ts: -------------------------------------------------------------------------------- 1 | import { CLIGlobal } from '../CLIGlobal.js'; 2 | 3 | /** 4 | * CLI CheckBox 5 | */ 6 | export class CLICheckBox extends CLIGlobal { 7 | id: string; 8 | 9 | labelText: string; 10 | beforeText: string; 11 | 12 | pickEvent: Function; 13 | selectEvent: Function; 14 | 15 | toggleState: boolean; 16 | 17 | public constructor({ text, bool = false, beforeText = `✅` }) { 18 | super(); 19 | 20 | this.labelText = text; 21 | this.id = this.generateId(); 22 | 23 | this.toggleState = bool; 24 | this.beforeText = beforeText; 25 | } 26 | 27 | /** 28 | * @param {'pick' | 'select'} type 29 | */ 30 | public on(type: string, event: Function = () => {}) { 31 | if (type === `pick`) this.pickEvent = event; 32 | if (type === `select`) this.selectEvent = event; 33 | } 34 | 35 | public return() { 36 | return { 37 | type: `checkbox`, 38 | 39 | id: this.id, 40 | 41 | text: this.labelText, 42 | beforeText: this.beforeText, 43 | 44 | pickEvent: this.pickEvent, 45 | selectEvent: this.selectEvent, 46 | 47 | toggleState: this.toggleState 48 | }; 49 | } 50 | } -------------------------------------------------------------------------------- /src/lib/CLIWidgets/CLIComboBox.ts: -------------------------------------------------------------------------------- 1 | import { CLIGlobal } from '../CLIGlobal.js'; 2 | 3 | /** 4 | * CLI ComboBox 5 | */ 6 | export class CLIComboBox extends CLIGlobal { 7 | id: string; 8 | 9 | labelText: string; 10 | beforeText: string; 11 | 12 | pickEvent: Function; 13 | selectEvent: Function; 14 | changeEvent: Function; 15 | 16 | toggleState: boolean; 17 | 18 | items: any[]; 19 | 20 | public constructor({ text, bool = false, beforeText = `✅` }) { 21 | super(); 22 | 23 | this.labelText = text; 24 | this.id = this.generateId(); 25 | this.items = []; 26 | this.toggleState = bool; 27 | this.beforeText = beforeText; 28 | } 29 | 30 | public addItem(item: any, { x = 0, y = 0 }) { 31 | item.name = this.id; 32 | item.x = x; 33 | item.y = y; 34 | 35 | this.items = [...this.items, item]; 36 | } 37 | 38 | /** 39 | * @param {'pick' | 'select' | 'change'} type 40 | */ 41 | public on(type: string, event: Function = () => {}) { 42 | if (type === `pick`) this.pickEvent = event; 43 | if (type === `select`) this.selectEvent = event; 44 | if (type === `change`) this.changeEvent = event; 45 | } 46 | 47 | public return() { 48 | return { 49 | type: `combobox`, 50 | 51 | id: this.id, 52 | 53 | text: this.labelText, 54 | beforeText: this.beforeText, 55 | 56 | pickEvent: this.pickEvent, 57 | selectEvent: this.selectEvent, 58 | changeEvent: this.changeEvent, 59 | 60 | items: this.items 61 | }; 62 | } 63 | } -------------------------------------------------------------------------------- /src/lib/CLIWidgets/CLIImage.ts: -------------------------------------------------------------------------------- 1 | // @ts-ignore 2 | 3 | import { CLIGlobal } from '../CLIGlobal.js'; 4 | import * as Jimp from 'jimp'; 5 | 6 | /** 7 | * CLI Image 8 | */ 9 | export class CLIImage extends CLIGlobal { 10 | id: string; 11 | 12 | text: string; 13 | 14 | Jimp: any; 15 | 16 | public constructor(url: string, { width, height }) { 17 | super(); 18 | 19 | this.Jimp = Jimp; 20 | this.image(url, width, height).then(data => { 21 | this.text = data; 22 | this.return(); 23 | }); 24 | this.id = this.generateId(); 25 | } 26 | 27 | public async image(path: string, width: number, height: number) { 28 | const image = await this.Jimp.default.read(path); 29 | image.resize(width, height); 30 | 31 | let asciiArt = ``; 32 | 33 | image.scan(0, 0, image.getWidth(), image.getHeight(), (x: number, y: number, idx: number) => { 34 | const red = image.bitmap.data[idx + 0]; 35 | const green = image.bitmap.data[idx + 1]; 36 | const blue = image.bitmap.data[idx + 2]; 37 | 38 | const asciiChar = red < 128 ? `#` : `-`; 39 | 40 | const textColor = `\x1b[38;2;${red};${green};${blue}m`; 41 | const resetColor = `\x1b[0m`; 42 | 43 | asciiArt += textColor + asciiChar + resetColor; 44 | 45 | if (x === image.getWidth() - 1) asciiArt += `\n`; 46 | }); 47 | 48 | return asciiArt; 49 | } 50 | 51 | public return() { 52 | return { 53 | type: `image`, 54 | 55 | id: this.id, 56 | 57 | text: this.text 58 | }; 59 | } 60 | } -------------------------------------------------------------------------------- /src/lib/CLIWidgets/CLILabel.ts: -------------------------------------------------------------------------------- 1 | import { CLIGlobal } from '../CLIGlobal.js'; 2 | 3 | /** 4 | * CLI Label 5 | */ 6 | export class CLILabel extends CLIGlobal { 7 | id: string; 8 | 9 | labelText: string; 10 | 11 | public constructor({ text }) { 12 | super(); 13 | 14 | this.labelText = text; 15 | this.id = this.generateId(); 16 | } 17 | 18 | public return() { 19 | return { 20 | type: `label`, 21 | 22 | id: this.id, 23 | 24 | text: this.labelText 25 | }; 26 | } 27 | } -------------------------------------------------------------------------------- /src/lib/CLIWidgets/CLIRadioButton.ts: -------------------------------------------------------------------------------- 1 | import { CLIGlobal } from '../CLIGlobal.js'; 2 | 3 | /** 4 | * CLI RadioButton 5 | */ 6 | export class CLIRadioButton extends CLIGlobal { 7 | id: string; 8 | 9 | name: string; 10 | 11 | labelText: string; 12 | beforeText: string; 13 | 14 | pickEvent: Function; 15 | selectEvent: Function; 16 | 17 | toggleState: boolean; 18 | 19 | public constructor({ text, name, bool = false, beforeText = `✅` }) { 20 | super(); 21 | 22 | this.labelText = text; 23 | this.id = this.generateId(); 24 | 25 | this.toggleState = bool; 26 | this.beforeText = beforeText; 27 | this.name = name; 28 | } 29 | 30 | /** 31 | * @param {'pick' | 'select'} type 32 | */ 33 | public on(type: string, event: Function = () => {}) { 34 | if (type === `pick`) this.pickEvent = event; 35 | if (type === `select`) this.selectEvent = event; 36 | } 37 | 38 | public return() { 39 | return { 40 | type: `radiobutton`, 41 | 42 | id: this.id, 43 | 44 | name: this.name, 45 | 46 | text: this.labelText, 47 | beforeText: this.beforeText, 48 | 49 | pickEvent: this.pickEvent, 50 | selectEvent: this.selectEvent, 51 | 52 | toggleState: this.toggleState 53 | }; 54 | } 55 | } -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2021", 4 | "module": "ESNext", 5 | "outDir": "./dist", 6 | "moduleResolution": "node" 7 | }, 8 | "include": ["src"] 9 | } --------------------------------------------------------------------------------