script
This commit is contained in:
parent
41e3b3fbcd
commit
dd9664d4ee
329
.eslintrc.js
329
.eslintrc.js
@ -16,322 +16,23 @@ module.exports = {
|
|||||||
plugins: ["@typescript-eslint"],
|
plugins: ["@typescript-eslint"],
|
||||||
ignorePatterns: ['NetscriptDefinitions.d.ts', '*.js'],
|
ignorePatterns: ['NetscriptDefinitions.d.ts', '*.js'],
|
||||||
rules: {
|
rules: {
|
||||||
"accessor-pairs": [
|
"@typescript-eslint/array-type": ["error", { "default": "array-simple" }],
|
||||||
|
"@typescript-eslint/ban-ts-comment": ["off"],
|
||||||
|
"@typescript-eslint/explicit-member-accessibility": ["off"],
|
||||||
|
"@typescript-eslint/explicit-module-boundary-types": ["off"],
|
||||||
|
"@typescript-eslint/no-non-null-assertion": ["off"],
|
||||||
|
"@typescript-eslint/no-use-before-define": ["off"],
|
||||||
|
"@typescript-eslint/no-parameter-properties": ["off"],
|
||||||
|
"@typescript-eslint/no-unused-vars": [
|
||||||
"error",
|
"error",
|
||||||
{
|
{ "argsIgnorePattern": "^_", "varsIgnorePattern": "^_" }
|
||||||
setWithoutGet: true,
|
|
||||||
getWithoutSet: false,
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
"array-bracket-newline": ["off"],
|
"@typescript-eslint/ban-ts-ignore": ["off"],
|
||||||
"array-bracket-spacing": ["off"],
|
"@typescript-eslint/no-empty-function": ["off"],
|
||||||
"array-callback-return": ["off"],
|
"no-return-await": "error",
|
||||||
"array-element-newline": ["off"],
|
"require-await": "error",
|
||||||
"arrow-body-style": ["off"],
|
"no-async-promise-executor": "error",
|
||||||
"arrow-parens": ["off"],
|
"no-constant-condition": ["off"]
|
||||||
"arrow-spacing": ["off"],
|
|
||||||
"block-scoped-var": ["off"],
|
|
||||||
"block-spacing": ["off"],
|
|
||||||
"brace-style": ["off"],
|
|
||||||
"callback-return": ["error"],
|
|
||||||
camelcase: ["off"],
|
|
||||||
"capitalized-comments": ["off"],
|
|
||||||
"class-methods-use-this": ["off"],
|
|
||||||
complexity: ["off"],
|
|
||||||
"consistent-return": ["off"],
|
|
||||||
"consistent-this": ["off"],
|
|
||||||
"constructor-super": ["error"],
|
|
||||||
curly: ["off"],
|
|
||||||
"default-case": ["off"],
|
|
||||||
"dot-notation": ["off"],
|
|
||||||
"eol-last": ["off"],
|
|
||||||
eqeqeq: ["off"],
|
|
||||||
"for-direction": ["error"],
|
|
||||||
"func-call-spacing": ["off"],
|
|
||||||
"func-name-matching": ["error"],
|
|
||||||
"func-names": ["off", "never"],
|
|
||||||
"func-style": ["off"],
|
|
||||||
"function-paren-newline": ["off"],
|
|
||||||
"getter-return": [
|
|
||||||
"error",
|
|
||||||
{
|
|
||||||
allowImplicit: false,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"global-require": ["off"],
|
|
||||||
"guard-for-in": ["off"],
|
|
||||||
"handle-callback-err": ["error"],
|
|
||||||
"id-blacklist": ["error"],
|
|
||||||
"id-length": ["off"],
|
|
||||||
"id-match": ["error"],
|
|
||||||
indent: ["off"],
|
|
||||||
"indent-legacy": ["off"],
|
|
||||||
"init-declarations": ["off"],
|
|
||||||
"key-spacing": ["off"],
|
|
||||||
"keyword-spacing": ["off"],
|
|
||||||
"line-comment-position": ["off"],
|
|
||||||
"linebreak-style": [
|
|
||||||
"off", // Line endings automatically converted to LF on git commit so probably shouldn't care about it here
|
|
||||||
],
|
|
||||||
"lines-around-comment": ["off"],
|
|
||||||
"lines-around-directive": ["error"],
|
|
||||||
"lines-between-class-members": ["error"],
|
|
||||||
"max-depth": ["off"],
|
|
||||||
"max-len": ["off"],
|
|
||||||
"max-lines": ["off"],
|
|
||||||
"max-nested-callbacks": ["error"],
|
|
||||||
"max-params": ["off"],
|
|
||||||
"max-statements": ["off"],
|
|
||||||
"max-statements-per-line": ["off"],
|
|
||||||
"multiline-comment-style": ["off", "starred-block"],
|
|
||||||
"multiline-ternary": ["off", "never"],
|
|
||||||
"new-cap": ["off"],
|
|
||||||
"new-parens": ["off"],
|
|
||||||
"newline-after-var": ["off"],
|
|
||||||
"newline-before-return": ["off"],
|
|
||||||
"newline-per-chained-call": ["off"],
|
|
||||||
"no-alert": ["error"],
|
|
||||||
"no-array-constructor": ["error"],
|
|
||||||
"no-await-in-loop": ["off"],
|
|
||||||
"no-bitwise": ["off"],
|
|
||||||
"no-buffer-constructor": ["error"],
|
|
||||||
"no-caller": ["error"],
|
|
||||||
"no-case-declarations": ["error"],
|
|
||||||
"no-catch-shadow": ["error"],
|
|
||||||
"no-class-assign": ["error"],
|
|
||||||
"no-compare-neg-zero": ["error"],
|
|
||||||
"no-confusing-arrow": ["error"],
|
|
||||||
"no-console": ["off"],
|
|
||||||
"no-const-assign": ["error"],
|
|
||||||
"no-constant-condition": [
|
|
||||||
"error",
|
|
||||||
{
|
|
||||||
checkLoops: false,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"no-continue": ["off"],
|
|
||||||
"no-control-regex": ["error"],
|
|
||||||
"no-debugger": ["error"],
|
|
||||||
"no-delete-var": ["error"],
|
|
||||||
"no-div-regex": ["error"],
|
|
||||||
"no-dupe-args": ["error"],
|
|
||||||
"no-dupe-class-members": ["error"],
|
|
||||||
"no-dupe-keys": ["error"],
|
|
||||||
"no-duplicate-case": ["error"],
|
|
||||||
"no-duplicate-imports": [
|
|
||||||
"error",
|
|
||||||
{
|
|
||||||
includeExports: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"no-else-return": ["off"],
|
|
||||||
"no-empty": [
|
|
||||||
"off",
|
|
||||||
{
|
|
||||||
allowEmptyCatch: false,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"no-empty-character-class": ["error"],
|
|
||||||
"no-empty-function": ["off"],
|
|
||||||
"no-empty-pattern": ["error"],
|
|
||||||
"no-eq-null": ["off"],
|
|
||||||
"no-ex-assign": ["off"],
|
|
||||||
"no-extra-boolean-cast": ["error"],
|
|
||||||
"no-extra-parens": ["off"],
|
|
||||||
"no-extra-semi": ["off"],
|
|
||||||
"no-eval": ["off"],
|
|
||||||
"no-extend-native": ["off"],
|
|
||||||
"no-extra-bind": ["error"],
|
|
||||||
"no-extra-label": ["error"],
|
|
||||||
"no-fallthrough": ["off"],
|
|
||||||
"no-floating-decimal": ["off"],
|
|
||||||
"no-func-assign": ["error"],
|
|
||||||
"no-global-assign": ["error"],
|
|
||||||
"no-implicit-coercion": ["off"],
|
|
||||||
"no-implicit-globals": ["error"],
|
|
||||||
"no-implied-eval": ["error"],
|
|
||||||
"no-inline-comments": ["off"],
|
|
||||||
"no-inner-declarations": ["off", "both"],
|
|
||||||
"no-invalid-regexp": ["error"],
|
|
||||||
"no-invalid-this": ["off"],
|
|
||||||
"no-irregular-whitespace": [
|
|
||||||
"error",
|
|
||||||
{
|
|
||||||
skipStrings: false,
|
|
||||||
skipComments: false,
|
|
||||||
skipRegExps: false,
|
|
||||||
skipTemplates: false,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"no-iterator": ["error"],
|
|
||||||
"no-label-var": ["error"],
|
|
||||||
"no-labels": ["off"],
|
|
||||||
"no-lone-blocks": ["error"],
|
|
||||||
"no-lonely-if": ["off"],
|
|
||||||
"no-loop-func": ["off"],
|
|
||||||
"no-magic-numbers": ["off"],
|
|
||||||
"no-mixed-operators": ["off"],
|
|
||||||
"no-mixed-requires": ["error"],
|
|
||||||
"no-mixed-spaces-and-tabs": ["off"],
|
|
||||||
"no-multi-assign": ["off"],
|
|
||||||
"no-multi-spaces": ["off"],
|
|
||||||
"no-multi-str": ["error"],
|
|
||||||
"no-multiple-empty-lines": [
|
|
||||||
"off",
|
|
||||||
{
|
|
||||||
max: 1,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"no-native-reassign": ["error"],
|
|
||||||
"no-negated-condition": ["off"],
|
|
||||||
"no-negated-in-lhs": ["error"],
|
|
||||||
"no-nested-ternary": ["off"],
|
|
||||||
"no-new": ["error"],
|
|
||||||
"no-new-func": ["error"],
|
|
||||||
"no-new-object": ["error"],
|
|
||||||
"no-new-require": ["error"],
|
|
||||||
"no-new-symbol": ["error"],
|
|
||||||
"no-new-wrappers": ["error"],
|
|
||||||
"no-octal": ["error"],
|
|
||||||
"no-octal-escape": ["error"],
|
|
||||||
"no-obj-calls": ["error"],
|
|
||||||
"no-param-reassign": ["off"],
|
|
||||||
"no-path-concat": ["error"],
|
|
||||||
"no-plusplus": ["off"],
|
|
||||||
"no-process-env": ["off"],
|
|
||||||
"no-process-exit": ["error"],
|
|
||||||
"no-proto": ["error"],
|
|
||||||
"no-prototype-builtins": ["off"],
|
|
||||||
"no-redeclare": ["off"],
|
|
||||||
"no-regex-spaces": ["error"],
|
|
||||||
"no-restricted-globals": ["error"],
|
|
||||||
"no-restricted-imports": ["error"],
|
|
||||||
"no-restricted-modules": ["error"],
|
|
||||||
"no-restricted-properties": [
|
|
||||||
"off",
|
|
||||||
{
|
|
||||||
object: "console",
|
|
||||||
property: "log",
|
|
||||||
message: "'log' is too general, use an appropriate level when logging.",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"no-restricted-syntax": ["error"],
|
|
||||||
"no-return-assign": ["off"],
|
|
||||||
"no-return-await": ["error"],
|
|
||||||
"no-script-url": ["error"],
|
|
||||||
"no-self-assign": [
|
|
||||||
"error",
|
|
||||||
{
|
|
||||||
props: false,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"no-self-compare": ["error"],
|
|
||||||
"no-sequences": ["error"],
|
|
||||||
"no-shadow": ["off"],
|
|
||||||
"no-shadow-restricted-names": ["error"],
|
|
||||||
"no-spaced-func": ["off"],
|
|
||||||
"no-sparse-arrays": ["error"],
|
|
||||||
"no-sync": ["error"],
|
|
||||||
"no-tabs": ["error"],
|
|
||||||
"no-template-curly-in-string": ["error"],
|
|
||||||
"no-ternary": ["off"],
|
|
||||||
"no-this-before-super": ["off"],
|
|
||||||
"no-throw-literal": ["error"],
|
|
||||||
"no-trailing-spaces": ["off"],
|
|
||||||
"no-undef": ["off"],
|
|
||||||
"no-undef-init": ["error"],
|
|
||||||
"no-undefined": ["off"],
|
|
||||||
"no-underscore-dangle": ["off"],
|
|
||||||
"no-unexpected-multiline": ["error"],
|
|
||||||
"no-unmodified-loop-condition": ["error"],
|
|
||||||
"no-unneeded-ternary": ["off"],
|
|
||||||
"no-unreachable": ["off"],
|
|
||||||
"no-unsafe-finally": ["error"],
|
|
||||||
"no-unsafe-negation": ["error"],
|
|
||||||
"no-unused-expressions": ["off"],
|
|
||||||
"no-unused-labels": ["error"],
|
|
||||||
"no-unused-vars": ["off"],
|
|
||||||
"no-use-before-define": ["off"],
|
|
||||||
"no-useless-call": ["off"],
|
|
||||||
"no-useless-computed-key": ["error"],
|
|
||||||
"no-useless-concat": ["off"],
|
|
||||||
"no-useless-constructor": ["error"],
|
|
||||||
"no-useless-escape": ["off"],
|
|
||||||
"no-useless-rename": [
|
|
||||||
"error",
|
|
||||||
{
|
|
||||||
ignoreDestructuring: false,
|
|
||||||
ignoreExport: false,
|
|
||||||
ignoreImport: false,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"no-useless-return": ["off"],
|
|
||||||
"no-var": ["off"],
|
|
||||||
"no-void": ["off"],
|
|
||||||
"no-warning-comments": ["off"],
|
|
||||||
"no-whitespace-before-property": ["error"],
|
|
||||||
"no-with": ["error"],
|
|
||||||
"nonblock-statement-body-position": ["off", "below"],
|
|
||||||
"object-curly-newline": ["off"],
|
|
||||||
"object-curly-spacing": ["off"],
|
|
||||||
"object-property-newline": ["off"],
|
|
||||||
"object-shorthand": ["off"],
|
|
||||||
"one-var": ["off"],
|
|
||||||
"one-var-declaration-per-line": ["off"],
|
|
||||||
"operator-assignment": ["off"],
|
|
||||||
"operator-linebreak": ["off", "none"],
|
|
||||||
"padded-blocks": ["off"],
|
|
||||||
"padding-line-between-statements": ["error"],
|
|
||||||
"prefer-arrow-callback": ["off"],
|
|
||||||
"prefer-const": ["off"],
|
|
||||||
"prefer-destructuring": ["off"],
|
|
||||||
"prefer-numeric-literals": ["error"],
|
|
||||||
"prefer-promise-reject-errors": ["off"],
|
|
||||||
"prefer-reflect": ["off"],
|
|
||||||
"prefer-rest-params": ["off"],
|
|
||||||
"prefer-spread": ["off"],
|
|
||||||
"prefer-template": ["off"],
|
|
||||||
"quote-props": ["off"],
|
|
||||||
quotes: ["off"],
|
|
||||||
radix: ["off", "as-needed"],
|
|
||||||
"require-await": ["off"],
|
|
||||||
"require-jsdoc": ["off"],
|
|
||||||
"require-yield": ["error"],
|
|
||||||
"rest-spread-spacing": ["error", "never"],
|
|
||||||
semi: ["warn", "never"],
|
|
||||||
"semi-spacing": ["off"],
|
|
||||||
"semi-style": ["error", "last"],
|
|
||||||
"sort-imports": ["off"],
|
|
||||||
"sort-keys": ["off"],
|
|
||||||
"sort-vars": ["off"],
|
|
||||||
"space-before-blocks": ["off"],
|
|
||||||
"space-before-function-paren": ["off"],
|
|
||||||
"space-in-parens": ["off"],
|
|
||||||
"space-infix-ops": ["off"],
|
|
||||||
"space-unary-ops": ["off"],
|
|
||||||
"spaced-comment": ["off"],
|
|
||||||
strict: ["off"],
|
|
||||||
"switch-colon-spacing": [
|
|
||||||
"error",
|
|
||||||
{
|
|
||||||
after: true,
|
|
||||||
before: false,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"symbol-description": ["error"],
|
|
||||||
"template-curly-spacing": ["error"],
|
|
||||||
"template-tag-spacing": ["error"],
|
|
||||||
"unicode-bom": ["error", "never"],
|
|
||||||
"use-isnan": ["error"],
|
|
||||||
"valid-jsdoc": ["off"],
|
|
||||||
"valid-typeof": ["error"],
|
|
||||||
"vars-on-top": ["off"],
|
|
||||||
"wrap-iife": ["error", "any"],
|
|
||||||
"wrap-regex": ["off"],
|
|
||||||
"yield-star-spacing": ["error", "before"],
|
|
||||||
yoda: ["error", "never"],
|
|
||||||
"@typescript-eslint/explicit-module-boundary-types": "off",
|
|
||||||
"@typescript-eslint/explicit-function-return-type": "off",
|
|
||||||
},
|
},
|
||||||
overrides: [
|
overrides: [
|
||||||
{
|
{
|
||||||
|
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@ -6,9 +6,12 @@
|
|||||||
"eslint.workingDirectories": ["./src"],
|
"eslint.workingDirectories": ["./src"],
|
||||||
"editor.codeActionsOnSave": {"source.fixAll.eslint": true},
|
"editor.codeActionsOnSave": {"source.fixAll.eslint": true},
|
||||||
|
|
||||||
|
"bitburner.authToken": "MOG9GEp4MGcw4aupPiqC6C9kd8jtFR2JgWcuS9JMyJjYfRCv0sqWdoB1H0G7HMQY",
|
||||||
|
"bitburner.fileWatcher.enable": true,
|
||||||
// Bitburner Extension Settings
|
// Bitburner Extension Settings
|
||||||
"bitburner.scriptRoot": "./dist/",
|
"bitburner.scriptRoot": "./dist/",
|
||||||
|
|
||||||
|
|
||||||
// Autosave Settings
|
// Autosave Settings
|
||||||
"files.autoSave": "off",
|
"files.autoSave": "off",
|
||||||
|
|
||||||
|
37
build.js
Normal file
37
build.js
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
const fs = require("fs");
|
||||||
|
const path = require("path");
|
||||||
|
const esbuild = require("esbuild");
|
||||||
|
const yargs = require("yargs");
|
||||||
|
yargs.scriptName("builder")
|
||||||
|
.usage("$0 <cmd> [args]")
|
||||||
|
.command("watch","watch and build",(yargs)=>{
|
||||||
|
|
||||||
|
},(argv)=>{
|
||||||
|
build({
|
||||||
|
watch:true,
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.command("build","build",(yargs)=>{},
|
||||||
|
(argv)=>{
|
||||||
|
build();
|
||||||
|
})
|
||||||
|
.help()
|
||||||
|
.argv;
|
||||||
|
|
||||||
|
async function build(options){
|
||||||
|
options = options || {};
|
||||||
|
options.watch = options.watch || false;
|
||||||
|
let dir = fs.readdirSync("src");
|
||||||
|
dir = dir.filter(x=>x.endsWith(".ts"));
|
||||||
|
|
||||||
|
await esbuild.build({
|
||||||
|
entryPoints:dir,
|
||||||
|
bundle:true,
|
||||||
|
write: true,
|
||||||
|
treeShaking: true,
|
||||||
|
watch: options.watch,
|
||||||
|
platform: "neutral",
|
||||||
|
target:"es2020",
|
||||||
|
outdir:"./dist",
|
||||||
|
});
|
||||||
|
}
|
12
package.json
12
package.json
@ -4,8 +4,7 @@
|
|||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"watch": "npx tsc -w",
|
"build": "node build.js",
|
||||||
"lint": "eslint . --ext .ts",
|
|
||||||
"defs": "node ./updateDefs.js"
|
"defs": "node ./updateDefs.js"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
@ -18,12 +17,13 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/SlyCedix/bitburner-typescript-template#readme",
|
"homepage": "https://github.com/SlyCedix/bitburner-typescript-template#readme",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/lodash": "^4.14.178",
|
|
||||||
"@types/node": "^16.4.3",
|
"@types/node": "^16.4.3",
|
||||||
|
"@types/yargs": "^17.0.11",
|
||||||
"@typescript-eslint/eslint-plugin": "^4.28.4",
|
"@typescript-eslint/eslint-plugin": "^4.28.4",
|
||||||
"@typescript-eslint/parser": "^4.28.4",
|
"@typescript-eslint/parser": "^4.28.4",
|
||||||
"eslint": "^7.31.0",
|
"esbuild": "^0.15.3"
|
||||||
"ts-node": "^9.1.1",
|
},
|
||||||
"typescript": "^4.3.5"
|
"dependencies": {
|
||||||
|
"yargs": "^17.5.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
15
src/auto-hacking.ts
Normal file
15
src/auto-hacking.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
|
||||||
|
import { selectHackableServerList, hackServer } from "./lib/hack"
|
||||||
|
import {isRootedServer} from "./lib/servers"
|
||||||
|
import {NS} from "@ns"
|
||||||
|
|
||||||
|
/** @param {NS} ns */
|
||||||
|
// eslint-disable-next-line require-await
|
||||||
|
export async function main(ns: NS): Promise<void> {
|
||||||
|
//ns.disableLog("ALL")
|
||||||
|
const servers = selectHackableServerList(ns).filter(x => !isRootedServer(x))
|
||||||
|
servers.forEach(x => {
|
||||||
|
ns.tprint(`hack ${x.hostname}`)
|
||||||
|
hackServer(ns, x)
|
||||||
|
})
|
||||||
|
}
|
6
src/get-share-power.ts
Normal file
6
src/get-share-power.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
import {NS} from "@ns"
|
||||||
|
|
||||||
|
// eslint-disable-next-line require-await
|
||||||
|
export async function main(ns:NS):Promise<void>{
|
||||||
|
ns.tprint(ns.getSharePower());
|
||||||
|
}
|
178
src/hacknet-daemon.ts
Normal file
178
src/hacknet-daemon.ts
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
import {NS} from "@ns"
|
||||||
|
import { parse } from "./lib/flag";
|
||||||
|
import {range} from "./util/range";
|
||||||
|
|
||||||
|
class Account{
|
||||||
|
value: number;
|
||||||
|
timer?: NodeJS.Timer;
|
||||||
|
constructor(value: number){
|
||||||
|
this.value = value;
|
||||||
|
this.timer = undefined;
|
||||||
|
}
|
||||||
|
startIncrement(ns:NS, rate: number): void{
|
||||||
|
this.timer = setInterval(()=>{
|
||||||
|
this.value += ns.hacknet.getNodeStats().production * rate;
|
||||||
|
},1000);
|
||||||
|
}
|
||||||
|
stopIncrement(): void{
|
||||||
|
clearInterval(this.timer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getNodeProduction(level: number, ram: number, cores: number, mult: number, bitMult:number): number{
|
||||||
|
const moneyGainPerLevel = 1.5;
|
||||||
|
const levelMult = level * moneyGainPerLevel;
|
||||||
|
const ramMult = Math.pow(1.035, ram - 1);
|
||||||
|
const coreMult = ((cores + 5) / 6);
|
||||||
|
return levelMult * ramMult * coreMult * mult * bitMult;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface HacknetNodeComponent<T> {
|
||||||
|
level: T;
|
||||||
|
core: T;
|
||||||
|
ram: T;
|
||||||
|
}
|
||||||
|
|
||||||
|
type ComponentKind = "level" | "core" | "ram";
|
||||||
|
|
||||||
|
export interface CEInfo {
|
||||||
|
upgradeCost : HacknetNodeComponent<number>;
|
||||||
|
production : HacknetNodeComponent<number>;
|
||||||
|
costEffective : HacknetNodeComponent<number>;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCostEffective(ns:NS, nodeIndex: number, n:number): CEInfo{
|
||||||
|
const coreUpgradeCost = ns.hacknet.getCoreUpgradeCost(nodeIndex,n);
|
||||||
|
const ramUpgradeCost = ns.hacknet.getRamUpgradeCost(nodeIndex,n);
|
||||||
|
const levelUpgradeCost = ns.hacknet.getLevelUpgradeCost(nodeIndex,n);
|
||||||
|
const mult = ns.getHacknetMultipliers().production;
|
||||||
|
const bitMult = 1//ns.getBitNodeMultipliers().HacknetNodeMoney;
|
||||||
|
const stat = ns.hacknet.getNodeStats(nodeIndex);
|
||||||
|
|
||||||
|
const coreProduction = getNodeProduction(stat.level, stat.ram, stat.cores + n, mult, bitMult) - stat.production;
|
||||||
|
const levelProduction = getNodeProduction(stat.level + n, stat.ram, stat.cores, mult, bitMult) - stat.production;
|
||||||
|
const ramProduction = getNodeProduction(stat.level, stat.ram * Math.pow(2,n), stat.cores, mult, bitMult) - stat.production;
|
||||||
|
|
||||||
|
return {
|
||||||
|
upgradeCost:{
|
||||||
|
core: coreUpgradeCost,
|
||||||
|
ram: ramUpgradeCost,
|
||||||
|
level: levelUpgradeCost,
|
||||||
|
},
|
||||||
|
production:{
|
||||||
|
core: coreProduction,
|
||||||
|
ram: ramProduction,
|
||||||
|
level: levelProduction,
|
||||||
|
},
|
||||||
|
costEffective:{
|
||||||
|
core: coreProduction/coreUpgradeCost,
|
||||||
|
ram: ramProduction/ramUpgradeCost,
|
||||||
|
level: levelProduction/levelUpgradeCost
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function createUpgradeAction(ns:NS, index: number, n: number, kind:ComponentKind):(account: Account)=>void{
|
||||||
|
return (account: Account)=>{
|
||||||
|
switch (kind) {
|
||||||
|
case "core":
|
||||||
|
account.value -= ns.hacknet.getCoreUpgradeCost(index,n);
|
||||||
|
ns.hacknet.upgradeCore(index,n)
|
||||||
|
break;
|
||||||
|
case "level":
|
||||||
|
account.value -= ns.hacknet.getLevelUpgradeCost(index,n);
|
||||||
|
ns.hacknet.upgradeLevel(index,n)
|
||||||
|
break;
|
||||||
|
case "ram":
|
||||||
|
account.value -= ns.hacknet.getRamUpgradeCost(index,n);
|
||||||
|
ns.hacknet.upgradeRam(index,n)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getMinCENode(ns:NS, index: number, n: number):[number,ComponentKind]{
|
||||||
|
const {costEffective: ce} = getCostEffective(ns,index,n);
|
||||||
|
if(ce.core < ce.level){
|
||||||
|
if(ce.core < ce.ram){
|
||||||
|
return [ce.core, "core"];
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
return [ce.ram, "ram"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if(ce.level < ce.ram){
|
||||||
|
return [ce.level,"level"];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return [ce.ram,"ram"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function* getIndexOfHackNode(ns:NS): Generator<number>{
|
||||||
|
for (const it of range(ns.hacknet.numNodes())) {
|
||||||
|
yield it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getMinCEIndex(ns:NS, n: number):[number,number,ComponentKind]{
|
||||||
|
let optimalC = Infinity;
|
||||||
|
let kind = "";
|
||||||
|
let minIndex = 0;
|
||||||
|
for(const it of getIndexOfHackNode(ns)){
|
||||||
|
const [c, k] = getMinCENode(ns,it,n);
|
||||||
|
if(c < optimalC){
|
||||||
|
optimalC = c;
|
||||||
|
kind = k;
|
||||||
|
minIndex = it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [minIndex,optimalC,kind];
|
||||||
|
}
|
||||||
|
|
||||||
|
function getBuyNodeCE(ns:NS):{cost:number;production:number;costEffective: number}{
|
||||||
|
const mult = ns.getHacknetMultipliers().production;
|
||||||
|
const bitMult = 1//ns.getBitNodeMultipliers().HacknetNodeMoney;
|
||||||
|
const cost = ns.hacknet.maxNumNodes() > ns.hacknet.numNodes() ? ns.hacknet.getPurchaseNodeCost() : Infinity;
|
||||||
|
const production = getNodeProduction(1,1,1,mult,bitMult);
|
||||||
|
return {
|
||||||
|
cost,
|
||||||
|
production,
|
||||||
|
costEffective: cost/production,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function cycle(ns:NS, account:Account): void{
|
||||||
|
const chunkN = 1;
|
||||||
|
|
||||||
|
const [upgradeNodeIndex,upgradeNodeCE,kind] = getMinCEIndex(ns,chunkN);
|
||||||
|
const {costEffective: buyNew} = getBuyNodeCE(ns);
|
||||||
|
if(upgradeNodeCE < buyNew){
|
||||||
|
const action = createUpgradeAction(ns,upgradeNodeIndex,chunkN,kind);
|
||||||
|
action(account);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ns.hacknet.purchaseNode()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line require-await
|
||||||
|
export async function main(ns:NS):Promise<void>{
|
||||||
|
ns.disableLog("ALL")
|
||||||
|
const flag = parse(ns.args);
|
||||||
|
const iter = parseInt(flag.i ?? flag.iter ?? "10");
|
||||||
|
const rate = parseFloat(flag.r ?? flag.rate ?? "0.5");
|
||||||
|
const budget = parseInt(flag.b ?? flag.budget ?? "0");
|
||||||
|
|
||||||
|
const account = new Account(budget);
|
||||||
|
account.startIncrement(ns,rate);
|
||||||
|
ns.tail();
|
||||||
|
for (let i = 0; i < iter; i++) {
|
||||||
|
ns.clearLog()
|
||||||
|
ns.print(`budget ${account.value}`);
|
||||||
|
cycle(ns,account);
|
||||||
|
await ns.sleep(1000);
|
||||||
|
}
|
||||||
|
}
|
455
src/lib/flag.ts
Normal file
455
src/lib/flag.ts
Normal file
@ -0,0 +1,455 @@
|
|||||||
|
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
|
||||||
|
/**
|
||||||
|
* CLI flag parser.
|
||||||
|
*
|
||||||
|
* This module is browser compatible.
|
||||||
|
*
|
||||||
|
* @module
|
||||||
|
*/
|
||||||
|
import { assert } from "../util/assert";
|
||||||
|
|
||||||
|
/** The value returned from `parse`. */
|
||||||
|
export interface Args {
|
||||||
|
/** Contains all the arguments that didn't have an option associated with
|
||||||
|
* them. */
|
||||||
|
_: Array<string | number>;
|
||||||
|
// deno-lint-ignore no-explicit-any
|
||||||
|
[key: string]: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The options for the `parse` call. */
|
||||||
|
export interface ParseOptions {
|
||||||
|
/** When `true`, populate the result `_` with everything before the `--` and
|
||||||
|
* the result `['--']` with everything after the `--`. Here's an example:
|
||||||
|
*
|
||||||
|
* ```ts
|
||||||
|
* // $ deno run example.ts -- a arg1
|
||||||
|
* import { parse } from "./mod.ts";
|
||||||
|
* console.dir(parse(Deno.args, { "--": false }));
|
||||||
|
* // output: { _: [ "a", "arg1" ] }
|
||||||
|
* console.dir(parse(Deno.args, { "--": true }));
|
||||||
|
* // output: { _: [], --: [ "a", "arg1" ] }
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* Defaults to `false`.
|
||||||
|
*/
|
||||||
|
"--"?: boolean;
|
||||||
|
|
||||||
|
/** An object mapping string names to strings or arrays of string argument
|
||||||
|
* names to use as aliases. */
|
||||||
|
alias?: Record<string, string | string[]>;
|
||||||
|
|
||||||
|
/** A boolean, string or array of strings to always treat as booleans. If
|
||||||
|
* `true` will treat all double hyphenated arguments without equal signs as
|
||||||
|
* `boolean` (e.g. affects `--foo`, not `-f` or `--foo=bar`) */
|
||||||
|
boolean?: boolean | string | string[];
|
||||||
|
|
||||||
|
/** An object mapping string argument names to default values. */
|
||||||
|
default?: Record<string, unknown>;
|
||||||
|
|
||||||
|
/** When `true`, populate the result `_` with everything after the first
|
||||||
|
* non-option. */
|
||||||
|
stopEarly?: boolean;
|
||||||
|
|
||||||
|
/** A string or array of strings argument names to always treat as strings. */
|
||||||
|
string?: string | string[];
|
||||||
|
|
||||||
|
/** A string or array of strings argument names to always treat as arrays.
|
||||||
|
* Collectable options can be used multiple times. All values will be
|
||||||
|
* colelcted into one array. If a non-collectable option is used multiple
|
||||||
|
* times, the last value is used. */
|
||||||
|
collect?: string | string[];
|
||||||
|
|
||||||
|
/** A string or array of strings argument names which can be negated
|
||||||
|
* by prefixing them with `--no-`, like `--no-config`. */
|
||||||
|
negatable?: string | string[];
|
||||||
|
|
||||||
|
/** A function which is invoked with a command line parameter not defined in
|
||||||
|
* the `options` configuration object. If the function returns `false`, the
|
||||||
|
* unknown option is not added to `parsedArgs`. */
|
||||||
|
unknown?: (arg: string, key?: string, value?: unknown) => unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Flags {
|
||||||
|
bools: Record<string, boolean>;
|
||||||
|
strings: Record<string, boolean>;
|
||||||
|
collect: Record<string, boolean>;
|
||||||
|
negatable: Record<string, boolean>;
|
||||||
|
unknownFn: (arg: string, key?: string, value?: unknown) => unknown;
|
||||||
|
allBools: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface NestedMapping {
|
||||||
|
[key: string]: NestedMapping | unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { hasOwn } = Object;
|
||||||
|
|
||||||
|
function get<T>(obj: Record<string, T>, key: string): T | undefined {
|
||||||
|
if (hasOwn(obj, key)) {
|
||||||
|
return obj[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getForce<T>(obj: Record<string, T>, key: string): T {
|
||||||
|
const v = get(obj, key);
|
||||||
|
assert(v != null);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isNumber(x: unknown): boolean {
|
||||||
|
if (typeof x === "number") return true;
|
||||||
|
if (/^0x[0-9a-f]+$/i.test(String(x))) return true;
|
||||||
|
return /^[-+]?(?:\d+(?:\.\d*)?|\.\d+)(e[-+]?\d+)?$/.test(String(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
function hasKey(obj: NestedMapping, keys: string[]): boolean {
|
||||||
|
let o = obj;
|
||||||
|
keys.slice(0, -1).forEach((key) => {
|
||||||
|
o = (get(o, key) ?? {}) as NestedMapping;
|
||||||
|
});
|
||||||
|
|
||||||
|
const key = keys[keys.length - 1];
|
||||||
|
return key in o;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Take a set of command line arguments, optionally with a set of options, and
|
||||||
|
* return an object representing the flags found in the passed arguments.
|
||||||
|
*
|
||||||
|
* By default any arguments starting with `-` or `--` are considered boolean
|
||||||
|
* flags. If the argument name is followed by an equal sign (`=`) it is
|
||||||
|
* considered a key-value pair. Any arguments which could not be parsed are
|
||||||
|
* available in the `_` property of the returned object.
|
||||||
|
*
|
||||||
|
* ```ts
|
||||||
|
* import { parse } from "./mod.ts";
|
||||||
|
* const parsedArgs = parse(Deno.args);
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* ```ts
|
||||||
|
* import { parse } from "./mod.ts";
|
||||||
|
* const parsedArgs = parse(["--foo", "--bar=baz", "--no-qux", "./quux.txt"]);
|
||||||
|
* // parsedArgs: { foo: true, bar: "baz", qux: false, _: ["./quux.txt"] }
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
export function parse(
|
||||||
|
args: string[],
|
||||||
|
{
|
||||||
|
"--": doubleDash = false,
|
||||||
|
alias = {},
|
||||||
|
boolean = false,
|
||||||
|
default: defaults = {},
|
||||||
|
stopEarly = false,
|
||||||
|
string = [],
|
||||||
|
collect = [],
|
||||||
|
negatable = [],
|
||||||
|
unknown = (i: string): unknown => i,
|
||||||
|
}: ParseOptions = {},
|
||||||
|
): Args {
|
||||||
|
const flags: Flags = {
|
||||||
|
bools: {},
|
||||||
|
strings: {},
|
||||||
|
unknownFn: unknown,
|
||||||
|
allBools: false,
|
||||||
|
collect: {},
|
||||||
|
negatable: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
if (boolean !== undefined) {
|
||||||
|
if (typeof boolean === "boolean") {
|
||||||
|
flags.allBools = !!boolean;
|
||||||
|
} else {
|
||||||
|
const booleanArgs = typeof boolean === "string" ? [boolean] : boolean;
|
||||||
|
|
||||||
|
for (const key of booleanArgs.filter(Boolean)) {
|
||||||
|
flags.bools[key] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const aliases: Record<string, string[]> = {};
|
||||||
|
if (alias !== undefined) {
|
||||||
|
for (const key in alias) {
|
||||||
|
const val = getForce(alias, key);
|
||||||
|
if (typeof val === "string") {
|
||||||
|
aliases[key] = [val];
|
||||||
|
} else {
|
||||||
|
aliases[key] = val;
|
||||||
|
}
|
||||||
|
for (const alias of getForce(aliases, key)) {
|
||||||
|
aliases[alias] = [key].concat(aliases[key].filter((y) => alias !== y));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string !== undefined) {
|
||||||
|
const stringArgs = typeof string === "string" ? [string] : string;
|
||||||
|
|
||||||
|
for (const key of stringArgs.filter(Boolean)) {
|
||||||
|
flags.strings[key] = true;
|
||||||
|
const alias = get(aliases, key);
|
||||||
|
if (alias) {
|
||||||
|
for (const al of alias) {
|
||||||
|
flags.strings[al] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (collect !== undefined) {
|
||||||
|
const collectArgs = typeof collect === "string" ? [collect] : collect;
|
||||||
|
|
||||||
|
for (const key of collectArgs.filter(Boolean)) {
|
||||||
|
flags.collect[key] = true;
|
||||||
|
const alias = get(aliases, key);
|
||||||
|
if (alias) {
|
||||||
|
for (const al of alias) {
|
||||||
|
flags.collect[al] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (negatable !== undefined) {
|
||||||
|
const negatableArgs = typeof negatable === "string"
|
||||||
|
? [negatable]
|
||||||
|
: negatable;
|
||||||
|
|
||||||
|
for (const key of negatableArgs.filter(Boolean)) {
|
||||||
|
flags.negatable[key] = true;
|
||||||
|
const alias = get(aliases, key);
|
||||||
|
if (alias) {
|
||||||
|
for (const al of alias) {
|
||||||
|
flags.negatable[al] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const argv: Args = { _: [] };
|
||||||
|
|
||||||
|
function argDefined(key: string, arg: string): boolean {
|
||||||
|
return (
|
||||||
|
(flags.allBools && /^--[^=]+$/.test(arg)) ||
|
||||||
|
get(flags.bools, key) ||
|
||||||
|
!!get(flags.strings, key) ||
|
||||||
|
!!get(aliases, key)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setKey(
|
||||||
|
obj: NestedMapping,
|
||||||
|
name: string,
|
||||||
|
value: unknown,
|
||||||
|
collect = true,
|
||||||
|
): void {
|
||||||
|
let o = obj;
|
||||||
|
const keys = name.split(".");
|
||||||
|
keys.slice(0, -1).forEach(function (key): void {
|
||||||
|
if (get(o, key) === undefined) {
|
||||||
|
o[key] = {};
|
||||||
|
}
|
||||||
|
o = get(o, key) as NestedMapping;
|
||||||
|
});
|
||||||
|
|
||||||
|
const key = keys[keys.length - 1];
|
||||||
|
const collectable = collect && !!get(flags.collect, name);
|
||||||
|
|
||||||
|
if (!collectable) {
|
||||||
|
o[key] = value;
|
||||||
|
} else if (get(o, key) === undefined) {
|
||||||
|
o[key] = [value];
|
||||||
|
} else if (Array.isArray(get(o, key))) {
|
||||||
|
(o[key] as unknown[]).push(value);
|
||||||
|
} else {
|
||||||
|
o[key] = [get(o, key), value];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setArg(
|
||||||
|
key: string,
|
||||||
|
val: unknown,
|
||||||
|
arg: string | undefined = undefined,
|
||||||
|
collect?: boolean,
|
||||||
|
): void {
|
||||||
|
if (arg && flags.unknownFn && !argDefined(key, arg)) {
|
||||||
|
if (flags.unknownFn(arg, key, val) === false) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const value = !get(flags.strings, key) && isNumber(val) ? Number(val) : val;
|
||||||
|
setKey(argv, key, value, collect);
|
||||||
|
|
||||||
|
const alias = get(aliases, key);
|
||||||
|
if (alias) {
|
||||||
|
for (const x of alias) {
|
||||||
|
setKey(argv, x, value, collect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function aliasIsBoolean(key: string): boolean {
|
||||||
|
return getForce(aliases, key).some(
|
||||||
|
(x) => typeof get(flags.bools, x) === "boolean",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let notFlags: string[] = [];
|
||||||
|
|
||||||
|
// all args after "--" are not parsed
|
||||||
|
if (args.includes("--")) {
|
||||||
|
notFlags = args.slice(args.indexOf("--") + 1);
|
||||||
|
args = args.slice(0, args.indexOf("--"));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < args.length; i++) {
|
||||||
|
const arg = args[i];
|
||||||
|
|
||||||
|
if (/^--.+=/.test(arg)) {
|
||||||
|
const m = arg.match(/^--([^=]+)=(.*)$/s);
|
||||||
|
assert(m != null);
|
||||||
|
const [, key, value] = m;
|
||||||
|
|
||||||
|
if (flags.bools[key]) {
|
||||||
|
const booleanValue = value !== "false";
|
||||||
|
setArg(key, booleanValue, arg);
|
||||||
|
} else {
|
||||||
|
setArg(key, value, arg);
|
||||||
|
}
|
||||||
|
} else if (
|
||||||
|
/^--no-.+/.test(arg) && get(flags.negatable, arg.replace(/^--no-/, ""))
|
||||||
|
) {
|
||||||
|
const m = arg.match(/^--no-(.+)/);
|
||||||
|
assert(m != null);
|
||||||
|
setArg(m[1], false, arg, false);
|
||||||
|
} else if (/^--.+/.test(arg)) {
|
||||||
|
const m = arg.match(/^--(.+)/);
|
||||||
|
assert(m != null);
|
||||||
|
const [, key] = m;
|
||||||
|
const next = args[i + 1];
|
||||||
|
if (
|
||||||
|
next !== undefined &&
|
||||||
|
!/^-/.test(next) &&
|
||||||
|
!get(flags.bools, key) &&
|
||||||
|
!flags.allBools &&
|
||||||
|
(get(aliases, key) ? !aliasIsBoolean(key) : true)
|
||||||
|
) {
|
||||||
|
setArg(key, next, arg);
|
||||||
|
i++;
|
||||||
|
} else if (/^(true|false)$/.test(next)) {
|
||||||
|
setArg(key, next === "true", arg);
|
||||||
|
i++;
|
||||||
|
} else {
|
||||||
|
setArg(key, get(flags.strings, key) ? "" : true, arg);
|
||||||
|
}
|
||||||
|
} else if (/^-[^-]+/.test(arg)) {
|
||||||
|
const letters = arg.slice(1, -1).split("");
|
||||||
|
|
||||||
|
let broken = false;
|
||||||
|
for (let j = 0; j < letters.length; j++) {
|
||||||
|
const next = arg.slice(j + 2);
|
||||||
|
|
||||||
|
if (next === "-") {
|
||||||
|
setArg(letters[j], next, arg);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (/[A-Za-z]/.test(letters[j]) && /=/.test(next)) {
|
||||||
|
setArg(letters[j], next.split(/=(.+)/)[1], arg);
|
||||||
|
broken = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
/[A-Za-z]/.test(letters[j]) &&
|
||||||
|
/-?\d+(\.\d*)?(e-?\d+)?$/.test(next)
|
||||||
|
) {
|
||||||
|
setArg(letters[j], next, arg);
|
||||||
|
broken = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (letters[j + 1] && letters[j + 1].match(/\W/)) {
|
||||||
|
setArg(letters[j], arg.slice(j + 2), arg);
|
||||||
|
broken = true;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
setArg(letters[j], get(flags.strings, letters[j]) ? "" : true, arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const [key] = arg.slice(-1);
|
||||||
|
if (!broken && key !== "-") {
|
||||||
|
if (
|
||||||
|
args[i + 1] &&
|
||||||
|
!/^(-|--)[^-]/.test(args[i + 1]) &&
|
||||||
|
!get(flags.bools, key) &&
|
||||||
|
(get(aliases, key) ? !aliasIsBoolean(key) : true)
|
||||||
|
) {
|
||||||
|
setArg(key, args[i + 1], arg);
|
||||||
|
i++;
|
||||||
|
} else if (args[i + 1] && /^(true|false)$/.test(args[i + 1])) {
|
||||||
|
setArg(key, args[i + 1] === "true", arg);
|
||||||
|
i++;
|
||||||
|
} else {
|
||||||
|
setArg(key, get(flags.strings, key) ? "" : true, arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!flags.unknownFn || flags.unknownFn(arg) !== false) {
|
||||||
|
argv._.push(flags.strings["_"] ?? !isNumber(arg) ? arg : Number(arg));
|
||||||
|
}
|
||||||
|
if (stopEarly) {
|
||||||
|
argv._.push(...args.slice(i + 1));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const [key, value] of Object.entries(defaults)) {
|
||||||
|
if (!hasKey(argv, key.split("."))) {
|
||||||
|
setKey(argv, key, value);
|
||||||
|
|
||||||
|
if (aliases[key]) {
|
||||||
|
for (const x of aliases[key]) {
|
||||||
|
setKey(argv, x, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const key of Object.keys(flags.bools)) {
|
||||||
|
if (!hasKey(argv, key.split("."))) {
|
||||||
|
const value = get(flags.collect, key) ? [] : false;
|
||||||
|
setKey(
|
||||||
|
argv,
|
||||||
|
key,
|
||||||
|
value,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const key of Object.keys(flags.strings)) {
|
||||||
|
if (!hasKey(argv, key.split(".")) && get(flags.collect, key)) {
|
||||||
|
setKey(
|
||||||
|
argv,
|
||||||
|
key,
|
||||||
|
[],
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (doubleDash) {
|
||||||
|
argv["--"] = [];
|
||||||
|
for (const key of notFlags) {
|
||||||
|
argv["--"].push(key);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (const key of notFlags) {
|
||||||
|
argv._.push(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return argv;
|
||||||
|
}
|
95
src/lib/hack.ts
Normal file
95
src/lib/hack.ts
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
import { NS, Server } from '@ns'
|
||||||
|
import {selectAllServerList, ServerInfo} from "./servers"
|
||||||
|
|
||||||
|
export type Hackability = "hackable" | "rooted" | "impossible"
|
||||||
|
|
||||||
|
export function getHackability(ns: NS,hostname:string): Hackability{
|
||||||
|
if (ns.hasRootAccess(hostname)) {
|
||||||
|
return "rooted";
|
||||||
|
}
|
||||||
|
if (ns.getServerRequiredHackingLevel(hostname) > ns.getHackingLevel() ||
|
||||||
|
ns.getServerNumPortsRequired(hostname) > hackablePorts(ns)) {
|
||||||
|
return "impossible";
|
||||||
|
}
|
||||||
|
return "hackable";
|
||||||
|
}
|
||||||
|
export function getHackabilityServer(ns: NS,server:Server): Hackability{
|
||||||
|
if (server.hasAdminRights) {
|
||||||
|
return "rooted";
|
||||||
|
}
|
||||||
|
if (server.requiredHackingSkill > ns.getHackingLevel() ||
|
||||||
|
server.numOpenPortsRequired > hackablePorts(ns)) {
|
||||||
|
return "impossible";
|
||||||
|
}
|
||||||
|
return "hackable";
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getLockSymbol(k:Hackability):string{
|
||||||
|
switch (k) {
|
||||||
|
case "rooted":
|
||||||
|
return "🔓"
|
||||||
|
case "hackable":
|
||||||
|
return "🔐"
|
||||||
|
case "impossible":
|
||||||
|
return "🔒"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Hack = {
|
||||||
|
file: string;
|
||||||
|
exec: (ns: NS, target:string)=> void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const hacks: Hack[] = [
|
||||||
|
{ file: 'BruteSSH.exe', exec: (ns: NS, target: string) => ns.brutessh(target) },
|
||||||
|
{ file: 'FTPCrack.exe', exec: (ns: NS, target: string) => ns.ftpcrack(target) },
|
||||||
|
{ file: 'relaySMTP.exe', exec: (ns: NS, target: string) => ns.relaysmtp(target) },
|
||||||
|
{ file: 'HTTPWorm.exe', exec: (ns: NS, target: string) => ns.httpworm(target) },
|
||||||
|
{ file: 'SQLInject.exe', exec: (ns: NS, target: string) => ns.sqlinject(target) },
|
||||||
|
]
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {NS} ns
|
||||||
|
*/
|
||||||
|
export function hackablePorts(ns: NS): number {
|
||||||
|
return hacks.map(x=>(ns.fileExists(x.file) ? 1 : 0)).reduce((x,y)=>x+y)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isHackableServer(ns: NS, target: Server): boolean{
|
||||||
|
return target.numOpenPortsRequired <= hackablePorts(ns) &&
|
||||||
|
target.hackDifficulty <= ns.getHackingLevel()
|
||||||
|
}
|
||||||
|
export function selectHackableServerList(ns: NS): ServerInfo[]{
|
||||||
|
return selectAllServerList(ns).filter(x=>{
|
||||||
|
return isHackableServer(ns,x)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function hackServer(ns:NS,target:Server);
|
||||||
|
export function hackServer(ns:NS,target:string);
|
||||||
|
export function hackServer(ns:NS,target:string|Server):void{
|
||||||
|
const hostname = typeof target === "string" ? target : target.hostname
|
||||||
|
hacks.forEach(x=>{
|
||||||
|
if(ns.fileExists(x.file,"home")){
|
||||||
|
x.exec(ns, hostname)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
ns.nuke(hostname)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @param {NS} ns */
|
||||||
|
// eslint-disable-next-line require-await
|
||||||
|
export async function main(ns: NS):Promise<void> {
|
||||||
|
if(ns.args.length == 0){
|
||||||
|
ns.tprint("argument required")
|
||||||
|
ns.tprint("run cmd [target]")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const target = ns.args[0]
|
||||||
|
hackServer(target)
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
export function autocomplete(data : ServerData, args : string[]) : string[] {
|
||||||
|
return [...data.servers]
|
||||||
|
}
|
71
src/lib/servers.ts
Normal file
71
src/lib/servers.ts
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
import { NS, Server } from '@ns'
|
||||||
|
|
||||||
|
/** @param {NS} ns */
|
||||||
|
export async function main(ns: NS): Promise<void> {
|
||||||
|
if (ns.args.length == 0) {
|
||||||
|
ns.tprint("argument required")
|
||||||
|
ns.tprint("search all server and print to json")
|
||||||
|
ns.tprint("run cmd [filePath]")
|
||||||
|
ns.exit()
|
||||||
|
}
|
||||||
|
const filePath = ns.args[0]
|
||||||
|
const collectedData = selectAllServerList()
|
||||||
|
const buf = JSON.stringify(collectedData, undefined, 2)
|
||||||
|
await ns.write(filePath, buf, "w")
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ServerInfo extends Server{
|
||||||
|
relHost:string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {NS} ns
|
||||||
|
* @param func
|
||||||
|
*/
|
||||||
|
export function visitAllServerList(ns: NS, func:(data: ServerInfo)=>void):void {
|
||||||
|
/** @type {string[]} */
|
||||||
|
const queue = ["home"]
|
||||||
|
/** @type {Set<string>} */
|
||||||
|
const visited = new Set()
|
||||||
|
|
||||||
|
//breadth first search
|
||||||
|
while (queue.length > 0) {
|
||||||
|
const vHost = queue.pop()
|
||||||
|
const data = getServersInfo(ns, vHost)
|
||||||
|
|
||||||
|
func(data)
|
||||||
|
|
||||||
|
visited.add(vHost)
|
||||||
|
for (const h of data.relHost) {
|
||||||
|
if (!visited.has(h)) {
|
||||||
|
queue.push(h)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**@param {NS} ns */
|
||||||
|
export function selectAllServerList(ns: NS): ServerInfo[] {
|
||||||
|
const collectedData: ServerInfo[] = []
|
||||||
|
visitAllServerList(ns, (data) => {
|
||||||
|
collectedData.push(data)
|
||||||
|
})
|
||||||
|
return collectedData
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isRootedServer(server:Server):boolean{
|
||||||
|
return server.hasAdminRights
|
||||||
|
}
|
||||||
|
|
||||||
|
export function selectRootedServerList(ns:NS): ServerInfo[]{
|
||||||
|
return selectAllServerList(ns).filter(isRootedServer)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @param {NS} ns
|
||||||
|
* @param {string} host
|
||||||
|
* @return {Server & {relHost: string[]}}
|
||||||
|
*/
|
||||||
|
export function getServersInfo(ns: NS, host: string): ServerInfo {
|
||||||
|
const neighbor = ns.scan(host)
|
||||||
|
const info = ns.getServer(host)
|
||||||
|
return { ...info, relHost: neighbor }
|
||||||
|
}
|
27
src/list-all-server.ts
Normal file
27
src/list-all-server.ts
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import {NS} from "@ns"
|
||||||
|
import {getHackability,getLockSymbol} from "./lib/hack";
|
||||||
|
|
||||||
|
/** @param {NS} ns */
|
||||||
|
// eslint-disable-next-line require-await
|
||||||
|
export async function main(ns: NS): Promise<void> {
|
||||||
|
findServer(ns, 'home', 'home', 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @param {NS} ns
|
||||||
|
* @param {string} startServer
|
||||||
|
* @param {string} targetServer
|
||||||
|
* @param {number} depth
|
||||||
|
*/
|
||||||
|
function findServer(ns: NS, startServer: string, targetServer: string, depth: number): void {
|
||||||
|
const servers = ns.scan(targetServer)
|
||||||
|
.filter((server) => server !== startServer);
|
||||||
|
servers.forEach((server) => {
|
||||||
|
const lock = getHackability(ns, server);
|
||||||
|
const lock_symbol = getLockSymbol(lock);
|
||||||
|
const info = ns.getServer(server);
|
||||||
|
ns.tprint(`😹${'>'.repeat(depth)} ${lock_symbol} ${server} ${info.backdoorInstalled ? '✅': '❌'}`);
|
||||||
|
if (lock !== "impossible") {
|
||||||
|
findServer(ns, targetServer, server, depth + 1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
13
src/list-purchase-server.ts
Normal file
13
src/list-purchase-server.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import {NS} from "@ns"
|
||||||
|
import {parse} from "lib/flag"
|
||||||
|
|
||||||
|
/** @param {NS} ns */
|
||||||
|
// eslint-disable-next-line require-await
|
||||||
|
export async function main(ns: NS):Promise<void> {
|
||||||
|
const flag = parse(ns.args);
|
||||||
|
if(flag.help || flag.h){
|
||||||
|
ns.tprint(`* list all purchased server`);
|
||||||
|
ns.exit();
|
||||||
|
}
|
||||||
|
ns.tprint(ns.getPurchasedServers().join("\n"));
|
||||||
|
}
|
72
src/purchase-server.ts
Normal file
72
src/purchase-server.ts
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
import { NS } from "@ns"
|
||||||
|
import {parse} from "./lib/flag"
|
||||||
|
import {range} from "./util/range";
|
||||||
|
|
||||||
|
|
||||||
|
/** @param {NS} ns */
|
||||||
|
export async function main(ns: NS): Promise<void> {
|
||||||
|
const flag = parse(ns.args);
|
||||||
|
if(flag.h || flag.help){
|
||||||
|
ns.tprint("script : purchase server")
|
||||||
|
ns.tprint("");
|
||||||
|
ns.exit()
|
||||||
|
}
|
||||||
|
if(Boolean(flag.i) || Boolean(flag.interactive)){
|
||||||
|
const ramLimit = ns.getPurchasedServerMaxRam()
|
||||||
|
const choices = [...range(3,20)].map(x=>Math.pow(2,x)).filter(x=>x <= ramLimit).map((x)=>{
|
||||||
|
const cost = ns.getPurchasedServerCost(x);
|
||||||
|
return `${x}GB (${ns.nFormat(cost,"$0.000a")})`
|
||||||
|
});
|
||||||
|
const choice = await ns.prompt("which server do you purchase?",{
|
||||||
|
type:"select",
|
||||||
|
choices
|
||||||
|
});
|
||||||
|
if(choice === ""){
|
||||||
|
ns.tprint("canceled");
|
||||||
|
ns.exit();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const gb = parseInt(/^(\d+)GB/.exec(choice)[1]);
|
||||||
|
ns.tprint("you select ",gb,"GB");
|
||||||
|
const hostname = await ns.prompt("name your server",{type:"text"});
|
||||||
|
if(hostname === ""){
|
||||||
|
ns.tprint("canceled");
|
||||||
|
ns.exit();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const p = await ns.prompt(
|
||||||
|
`do you want to purchase server ${gb}GB(${
|
||||||
|
ns.nFormat(ns.getPurchasedServerCost(gb),"$0.000a")})?`,
|
||||||
|
{ type: "boolean" });
|
||||||
|
if (p) {
|
||||||
|
const l = ns.purchaseServer(hostname, ram)
|
||||||
|
ns.tprint(l, " purchased");
|
||||||
|
}
|
||||||
|
ns.exit()
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((flag.n || flag.name) && (flag.s || flag.size)) {
|
||||||
|
ns.tprint("argument needed")
|
||||||
|
ns.tprint("run cmd -n [hostname] -s [ram(GB)]")
|
||||||
|
ns.tprint("run cmd --name [hostname] --size [ram(GB)]")
|
||||||
|
ns.exit()
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const hostname = flag.n ?? flag.name
|
||||||
|
const ram = parseInt(flag.s ?? flag.size)
|
||||||
|
if(isNaN(ram)){
|
||||||
|
ns.tprint("size must be integer!");
|
||||||
|
ns.exit();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const f = ns.getPurchasedServerCost(ram)
|
||||||
|
const ff = ns.nFormat(f, "($ 0.00 a)")
|
||||||
|
const p = await ns.prompt("required : " + ff + "\ndo you want to purchase server " + ram + "GB?",
|
||||||
|
{ type: "boolean" })
|
||||||
|
if (p) {
|
||||||
|
const l = ns.purchaseServer(hostname, ram)
|
||||||
|
ns.tprint(l, " purchased")
|
||||||
|
}
|
||||||
|
}
|
79
src/server-status.ts
Normal file
79
src/server-status.ts
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
import {NS} from "@ns";
|
||||||
|
import {hackablePorts, getHackability, getLockSymbol} from "./lib/hack";
|
||||||
|
import {parse} from "./lib/flag";
|
||||||
|
|
||||||
|
|
||||||
|
type ReportOption = {
|
||||||
|
detail?: boolean;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Utility functions that report serverStatus
|
||||||
|
* and Hackability
|
||||||
|
* @param {NS} ns
|
||||||
|
*/
|
||||||
|
// eslint-disable-next-line require-await
|
||||||
|
export async function main(ns: NS): Promise<void> {
|
||||||
|
const flag = parse(ns.args);
|
||||||
|
if (flag._.length == 0) {
|
||||||
|
ns.tprint("argumented required");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const hostname = flag._[0];
|
||||||
|
const detail = Boolean(flag.d) || Boolean(flag.detail);
|
||||||
|
serverReport(ns, hostname,{
|
||||||
|
detail: detail,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @param {NS} ns
|
||||||
|
* @param {string} hostname
|
||||||
|
*/
|
||||||
|
export function serverReport(ns: NS, hostname: string, options?:ReportOption):void {
|
||||||
|
options ??= {};
|
||||||
|
const serverLock = getHackability(ns, hostname);
|
||||||
|
ns.tprint(`${getLockSymbol(serverLock)} ${hostname}`);
|
||||||
|
if(options.detail){
|
||||||
|
const server = ns.getServer(hostname);
|
||||||
|
const msg = ['',
|
||||||
|
`hostname : ${server.hostname}(${server.ip})`,
|
||||||
|
`🛡️${ns.nFormat(server.hackDifficulty,"0[.]000")}/${server.minDifficulty}(${server.baseDifficulty})`,
|
||||||
|
`💸${ns.nFormat(server.moneyAvailable,"$0.000a")}/${ns.nFormat(server.moneyMax,"$0.000a")}`,
|
||||||
|
`💾${server.ramUsed}GB/${server.maxRam}GB`,
|
||||||
|
`backdoorInstalled \t: ${server.backdoorInstalled ? `🚪` : `❌`}`,
|
||||||
|
`cpu \t\t\t: ${server.cpuCores}`,
|
||||||
|
`growth \t\t\t: ${server.serverGrowth}`,
|
||||||
|
`organization name\t: ${server.organizationName}`,
|
||||||
|
`purchased \t\t: ${server.purchasedByPlayer}`,
|
||||||
|
`required hacking skill\t: ${server.requiredHackingSkill}`,
|
||||||
|
`ports \t\t\t: ${server.openPortCount}/${server.numOpenPortsRequired}`
|
||||||
|
].join("\n");
|
||||||
|
ns.tprint(msg);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
if (serverLock == "rooted") {
|
||||||
|
ns.tprint(`🛡️${Math.round(ns.getServerSecurityLevel(hostname))}/${ns.getServerMinSecurityLevel(hostname)}`);
|
||||||
|
ns.tprint(`💸${ns.nFormat(ns.getServerMoneyAvailable(hostname), "$0.000a")}/${ns.nFormat(ns.getServerMaxMoney(hostname), "$0.000a")}`);
|
||||||
|
} else {
|
||||||
|
ns.tprint(`Hack Level: ${ns.getServerRequiredHackingLevel(hostname)}`);
|
||||||
|
ns.tprint(`Ports: ${ns.getServerNumPortsRequired(hostname)}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @param {NS} ns
|
||||||
|
*/
|
||||||
|
export function serverHackStatus(ns: NS, server: string): string {
|
||||||
|
if (ns.hasRootAccess(server)) {
|
||||||
|
return "🔓";
|
||||||
|
}
|
||||||
|
if (ns.getServerRequiredHackingLevel(server) > ns.getHackingLevel() ||
|
||||||
|
ns.getServerNumPortsRequired(server) > hackablePorts(ns)) {
|
||||||
|
return "🔒";
|
||||||
|
}
|
||||||
|
return "🔐";
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
export function autocomplete(data : ServerData, args : string[]) : string[] {
|
||||||
|
return [...data.servers]
|
||||||
|
}
|
8
src/share-server.ts
Normal file
8
src/share-server.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import {NS} from "@ns"
|
||||||
|
|
||||||
|
// eslint-disable-next-line require-await
|
||||||
|
export async function main(ns:NS):Promise<void>{
|
||||||
|
while(true){
|
||||||
|
await ns.share()
|
||||||
|
}
|
||||||
|
}
|
14
src/util/assert.ts
Normal file
14
src/util/assert.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import assert from "assert";
|
||||||
|
|
||||||
|
export class AssertionError extends Error{
|
||||||
|
constructor(msg:string){
|
||||||
|
super(msg);
|
||||||
|
this.name = "AssertionError";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function assert(expr: unknown, msg=""): asserts expr{
|
||||||
|
if(!expr){
|
||||||
|
throw new AssertionError(msg)
|
||||||
|
}
|
||||||
|
}
|
9
src/util/range.ts
Normal file
9
src/util/range.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
export function* range(end: number): Generator<number>;
|
||||||
|
export function* range(begin:number,end:number): Generator<number>;
|
||||||
|
export function* range(arg1: number, arg2?: number): Generator<number>{
|
||||||
|
const begin = arg2 ? arg1 : 0;
|
||||||
|
const end = arg2 ?? arg1;
|
||||||
|
for(let i = begin; i<end; i++){
|
||||||
|
yield i;
|
||||||
|
}
|
||||||
|
}
|
@ -6,15 +6,15 @@ export async function main(ns: NS): Promise<void> {
|
|||||||
const files = ns.ls('home', '.js')
|
const files = ns.ls('home', '.js')
|
||||||
for (const file of files) {
|
for (const file of files) {
|
||||||
const contents = ns.read(file)
|
const contents = ns.read(file)
|
||||||
hashes[file] = getHash(contents)
|
hashes[file] = getHash(contents as string)
|
||||||
}
|
}
|
||||||
|
// eslint-disable-next-line no-constant-condition
|
||||||
while (true) {
|
while (true) {
|
||||||
const files = ns.ls('home', '.js')
|
const files = ns.ls('home', '.js')
|
||||||
|
|
||||||
for (const file of files) {
|
for (const file of files) {
|
||||||
const contents = ns.read(file)
|
const contents = ns.read(file)
|
||||||
const hash = getHash(contents)
|
const hash = getHash(contents as string)
|
||||||
|
|
||||||
if (hash != hashes[file]) {
|
if (hash != hashes[file]) {
|
||||||
ns.tprintf(`INFO: Detected change in ${file}`)
|
ns.tprintf(`INFO: Detected change in ${file}`)
|
||||||
|
@ -11,7 +11,6 @@
|
|||||||
"noImplicitThis": true,
|
"noImplicitThis": true,
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"inlineSourceMap": true,
|
"inlineSourceMap": true,
|
||||||
"sourceRoot": "http://localhost:8000/sources/",
|
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"rootDir": "src/",
|
"rootDir": "src/",
|
||||||
"outDir": "dist/",
|
"outDir": "dist/",
|
||||||
|
Loading…
Reference in New Issue
Block a user