diff --git a/.vscode/extensions.json b/.vscode/extensions.json index fa017edecf42..79a1a64683a3 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -6,6 +6,7 @@ "dbaeumer.vscode-eslint", "stylemistake.auto-comment-blocks", "Donkie.vscode-tgstation-test-adapter", - "anturk.dmi-editor" + "anturk.dmi-editor", + "esbenp.prettier-vscode" ] } diff --git a/.vscode/settings.json b/.vscode/settings.json index 11e44342bd85..972f4b0aaa8b 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -14,15 +14,43 @@ }, "files.eol": "\n", "files.insertFinalNewline": true, - "gitlens.advanced.blame.customArguments": ["-w"], + "gitlens.advanced.blame.customArguments": [ + "-w" + ], "tgstationTestExplorer.project.resultsType": "json", "[javascript]": { - "editor.rulers": [80] + "editor.rulers": [ + 80 + ], + "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.formatOnSave": true + }, + "[javascriptreact]": { + "editor.rulers": [ + 80 + ], + "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.formatOnSave": true }, "[typescript]": { - "editor.rulers": [80] + "editor.rulers": [ + 80 + ], + "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.formatOnSave": true + }, + "[typescriptreact]": { + "editor.rulers": [ + 80 + ], + "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.formatOnSave": true }, "[scss]": { - "editor.rulers": [80] + "editor.rulers": [ + 80 + ], + "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.formatOnSave": true } } diff --git a/tgui/.eslintrc.yml b/tgui/.eslintrc.yml index 0288a4b58cbd..4dfc54e854c5 100644 --- a/tgui/.eslintrc.yml +++ b/tgui/.eslintrc.yml @@ -17,7 +17,6 @@ settings: react: version: '16.10' rules: - ## Possible Errors ## ---------------------------------------- ## Enforce “for” loop update clause moving the counter in the right @@ -308,13 +307,16 @@ rules: ## Enforce or disallow capitalization of the first letter of a comment # capitalized-comments: error ## Require or disallow trailing commas - comma-dangle: [error, { - arrays: always-multiline, - objects: always-multiline, - imports: always-multiline, - exports: always-multiline, - functions: only-multiline, ## Optional on functions - }] + comma-dangle: [ + error, + { + arrays: always-multiline, + objects: always-multiline, + imports: always-multiline, + exports: always-multiline, + functions: only-multiline, ## Optional on functions + }, + ] ## Enforce consistent spacing before and after commas comma-spacing: [error, { before: false, after: true }] ## Enforce consistent comma style @@ -349,10 +351,10 @@ rules: ## Enforce the location of arrow function bodies # implicit-arrow-linebreak: error ## Enforce consistent indentation - indent: [error, 2, { SwitchCase: 1 }] + #indent: [error, 2, { SwitchCase: 1 }] ## Enforce the consistent use of either double or single quotes in JSX ## attributes - jsx-quotes: [error, prefer-double] + # jsx-quotes: [error, prefer-double] ## Enforce consistent spacing between keys and values in object literal ## properties key-spacing: [error, { beforeColon: false, afterColon: true }] @@ -369,14 +371,17 @@ rules: ## Enforce a maximum depth that blocks can be nested # max-depth: error ## Enforce a maximum line length - max-len: [error, { - code: 200, - ## Ignore imports - ignorePattern: '^(import\s.+\sfrom\s|.*require\()', - ignoreUrls: true, - ignoreRegExpLiterals: true, - ignoreStrings: true, - }] + max-len: [ + error, + { + code: 200, + ## Ignore imports + ignorePattern: '^(import\s.+\sfrom\s|.*require\()', + ignoreUrls: true, + ignoreRegExpLiterals: true, + ignoreStrings: true, + }, + ] ## Enforce a maximum number of lines per file # max-lines: error ## Enforce a maximum number of line of code in a function @@ -413,7 +418,7 @@ rules: ## Disallow mixed binary operators # no-mixed-operators: error ## Disallow mixed spaces and tabs for indentation - no-mixed-spaces-and-tabs: error + # no-mixed-spaces-and-tabs: error ## Disallow use of chained assignment expressions # no-multi-assign: error ## Disallow multiple empty lines @@ -439,13 +444,13 @@ rules: ## Disallow ternary operators when simpler alternatives exist # no-unneeded-ternary: error ## Disallow whitespace before properties - no-whitespace-before-property: error + # no-whitespace-before-property: error ## Enforce the location of single-line statements # nonblock-statement-body-position: error ## Enforce consistent line breaks inside braces # object-curly-newline: [error, { multiline: true }] ## Enforce consistent spacing inside braces - object-curly-spacing: [error, always] + #object-curly-spacing: [error, always] ## Enforce placing object properties on separate lines # object-property-newline: error ## Enforce variables to be declared either together or separately in @@ -456,7 +461,7 @@ rules: ## Require or disallow assignment operator shorthand where possible # operator-assignment: error ## Enforce consistent linebreak style for operators - operator-linebreak: [error, before] + #operator-linebreak: [error, before] ## Require or disallow padding within blocks # padded-blocks: error ## Require or disallow padding lines between statements @@ -479,15 +484,12 @@ rules: ## Require variables within the same declaration block to be sorted # sort-vars: error ## Enforce consistent spacing before blocks - space-before-blocks: [error, always] + #space-before-blocks: [error, always] ## Enforce consistent spacing before function definition opening parenthesis - space-before-function-paren: [error, { - anonymous: always, - named: never, - asyncArrow: always, - }] + #space-before-function-paren: + # [error, { anonymous: always, named: never, asyncArrow: always }] ## Enforce consistent spacing inside parentheses - space-in-parens: [error, never] + #space-in-parens: [error, never] ## Require spacing around infix operators # space-infix-ops: error ## Enforce consistent spacing before or after unary operators @@ -694,7 +696,7 @@ rules: react/jsx-closing-tag-location: error ## Enforce or disallow newlines inside of curly braces in JSX attributes and ## expressions (fixable) - react/jsx-curly-newline: error + #react/jsx-curly-newline: error ## Enforce or disallow spaces inside of curly braces in JSX attributes and ## expressions (fixable) react/jsx-curly-spacing: error @@ -707,11 +709,9 @@ rules: ## Enforce event handler naming conventions in JSX react/jsx-handler-names: error ## Validate JSX indentation (fixable) - react/jsx-indent: [error, 2, { - checkAttributes: true, - }] + #react/jsx-indent: [error, 2, { checkAttributes: true }] ## Validate props indentation in JSX (fixable) - react/jsx-indent-props: [error, 2] + #react/jsx-indent-props: [error, 2] ## Validate JSX has key prop when in array or iterator react/jsx-key: error ## Validate JSX maximum depth @@ -760,3 +760,4 @@ rules: ## Prevents the use of unused imports. ## This could be done by enabling no-unused-vars, but we're doing this for now unused-imports/no-unused-imports: error +extends: prettier diff --git a/tgui/.prettierignore b/tgui/.prettierignore new file mode 100644 index 000000000000..6b0296ceb475 --- /dev/null +++ b/tgui/.prettierignore @@ -0,0 +1,13 @@ +## NPM +/**/node_modules + +## Yarn +/.yarn +/yarn.lock +/.pnp.* + +.swcrc +/docs +/public +/packages/tgui-polyfill +/packages/tgfont/static diff --git a/tgui/.prettierrc.yml b/tgui/.prettierrc.yml index fe51f01cc4db..01769692264f 100644 --- a/tgui/.prettierrc.yml +++ b/tgui/.prettierrc.yml @@ -1,12 +1 @@ -arrowParens: always -bracketSpacing: true -endOfLine: lf -jsxBracketSameLine: true -jsxSingleQuote: false -printWidth: 80 -proseWrap: preserve -quoteProps: preserve -semi: true singleQuote: true -tabWidth: 2 -trailingComma: es5 diff --git a/tgui/.yarn/sdks/eslint/bin/eslint.js b/tgui/.yarn/sdks/eslint/bin/eslint.js index 4d327a49a06d..9ef98e400b47 100644 --- a/tgui/.yarn/sdks/eslint/bin/eslint.js +++ b/tgui/.yarn/sdks/eslint/bin/eslint.js @@ -1,13 +1,13 @@ #!/usr/bin/env node const {existsSync} = require(`fs`); -const {createRequire, createRequireFromPath} = require(`module`); +const {createRequire} = require(`module`); const {resolve} = require(`path`); const relPnpApiPath = "../../../../.pnp.cjs"; const absPnpApiPath = resolve(__dirname, relPnpApiPath); -const absRequire = (createRequire || createRequireFromPath)(absPnpApiPath); +const absRequire = createRequire(absPnpApiPath); if (existsSync(absPnpApiPath)) { if (!process.versions.pnp) { diff --git a/tgui/.yarn/sdks/eslint/lib/api.js b/tgui/.yarn/sdks/eslint/lib/api.js index 97a052442a86..653b22bae06f 100644 --- a/tgui/.yarn/sdks/eslint/lib/api.js +++ b/tgui/.yarn/sdks/eslint/lib/api.js @@ -1,20 +1,20 @@ #!/usr/bin/env node const {existsSync} = require(`fs`); -const {createRequire, createRequireFromPath} = require(`module`); +const {createRequire} = require(`module`); const {resolve} = require(`path`); const relPnpApiPath = "../../../../.pnp.cjs"; const absPnpApiPath = resolve(__dirname, relPnpApiPath); -const absRequire = (createRequire || createRequireFromPath)(absPnpApiPath); +const absRequire = createRequire(absPnpApiPath); if (existsSync(absPnpApiPath)) { if (!process.versions.pnp) { - // Setup the environment to be able to require eslint/lib/api.js + // Setup the environment to be able to require eslint require(absPnpApiPath).setup(); } } -// Defer to the real eslint/lib/api.js your application uses -module.exports = absRequire(`eslint/lib/api.js`); +// Defer to the real eslint your application uses +module.exports = absRequire(`eslint`); diff --git a/tgui/.yarn/sdks/eslint/package.json b/tgui/.yarn/sdks/eslint/package.json index 744a77321030..b29322a1ffb3 100644 --- a/tgui/.yarn/sdks/eslint/package.json +++ b/tgui/.yarn/sdks/eslint/package.json @@ -2,5 +2,8 @@ "name": "eslint", "version": "7.32.0-sdk", "main": "./lib/api.js", - "type": "commonjs" + "type": "commonjs", + "bin": { + "eslint": "./bin/eslint.js" + } } diff --git a/tgui/.yarn/sdks/prettier/bin/prettier.cjs b/tgui/.yarn/sdks/prettier/bin/prettier.cjs new file mode 100644 index 000000000000..5efad688e739 --- /dev/null +++ b/tgui/.yarn/sdks/prettier/bin/prettier.cjs @@ -0,0 +1,20 @@ +#!/usr/bin/env node + +const {existsSync} = require(`fs`); +const {createRequire} = require(`module`); +const {resolve} = require(`path`); + +const relPnpApiPath = "../../../../.pnp.cjs"; + +const absPnpApiPath = resolve(__dirname, relPnpApiPath); +const absRequire = createRequire(absPnpApiPath); + +if (existsSync(absPnpApiPath)) { + if (!process.versions.pnp) { + // Setup the environment to be able to require prettier/bin/prettier.cjs + require(absPnpApiPath).setup(); + } +} + +// Defer to the real prettier/bin/prettier.cjs your application uses +module.exports = absRequire(`prettier/bin/prettier.cjs`); diff --git a/tgui/.yarn/sdks/prettier/index.cjs b/tgui/.yarn/sdks/prettier/index.cjs new file mode 100644 index 000000000000..8758e367a725 --- /dev/null +++ b/tgui/.yarn/sdks/prettier/index.cjs @@ -0,0 +1,20 @@ +#!/usr/bin/env node + +const {existsSync} = require(`fs`); +const {createRequire} = require(`module`); +const {resolve} = require(`path`); + +const relPnpApiPath = "../../../.pnp.cjs"; + +const absPnpApiPath = resolve(__dirname, relPnpApiPath); +const absRequire = createRequire(absPnpApiPath); + +if (existsSync(absPnpApiPath)) { + if (!process.versions.pnp) { + // Setup the environment to be able to require prettier + require(absPnpApiPath).setup(); + } +} + +// Defer to the real prettier your application uses +module.exports = absRequire(`prettier`); diff --git a/tgui/.yarn/sdks/prettier/package.json b/tgui/.yarn/sdks/prettier/package.json new file mode 100644 index 000000000000..6e68f38b6716 --- /dev/null +++ b/tgui/.yarn/sdks/prettier/package.json @@ -0,0 +1,7 @@ +{ + "name": "prettier", + "version": "3.2.5-sdk", + "main": "./index.cjs", + "type": "commonjs", + "bin": "./bin/prettier.cjs" +} diff --git a/tgui/.yarn/sdks/typescript/bin/tsc b/tgui/.yarn/sdks/typescript/bin/tsc index 5608e5743072..454b950b7e8f 100644 --- a/tgui/.yarn/sdks/typescript/bin/tsc +++ b/tgui/.yarn/sdks/typescript/bin/tsc @@ -1,13 +1,13 @@ #!/usr/bin/env node const {existsSync} = require(`fs`); -const {createRequire, createRequireFromPath} = require(`module`); +const {createRequire} = require(`module`); const {resolve} = require(`path`); const relPnpApiPath = "../../../../.pnp.cjs"; const absPnpApiPath = resolve(__dirname, relPnpApiPath); -const absRequire = (createRequire || createRequireFromPath)(absPnpApiPath); +const absRequire = createRequire(absPnpApiPath); if (existsSync(absPnpApiPath)) { if (!process.versions.pnp) { diff --git a/tgui/.yarn/sdks/typescript/bin/tsserver b/tgui/.yarn/sdks/typescript/bin/tsserver index cd7d557d523d..d7a605684df9 100644 --- a/tgui/.yarn/sdks/typescript/bin/tsserver +++ b/tgui/.yarn/sdks/typescript/bin/tsserver @@ -1,13 +1,13 @@ #!/usr/bin/env node const {existsSync} = require(`fs`); -const {createRequire, createRequireFromPath} = require(`module`); +const {createRequire} = require(`module`); const {resolve} = require(`path`); const relPnpApiPath = "../../../../.pnp.cjs"; const absPnpApiPath = resolve(__dirname, relPnpApiPath); -const absRequire = (createRequire || createRequireFromPath)(absPnpApiPath); +const absRequire = createRequire(absPnpApiPath); if (existsSync(absPnpApiPath)) { if (!process.versions.pnp) { diff --git a/tgui/.yarn/sdks/typescript/lib/tsc.js b/tgui/.yarn/sdks/typescript/lib/tsc.js index 16042d01d4fe..2f62fc96c0a0 100644 --- a/tgui/.yarn/sdks/typescript/lib/tsc.js +++ b/tgui/.yarn/sdks/typescript/lib/tsc.js @@ -1,13 +1,13 @@ #!/usr/bin/env node const {existsSync} = require(`fs`); -const {createRequire, createRequireFromPath} = require(`module`); +const {createRequire} = require(`module`); const {resolve} = require(`path`); const relPnpApiPath = "../../../../.pnp.cjs"; const absPnpApiPath = resolve(__dirname, relPnpApiPath); -const absRequire = (createRequire || createRequireFromPath)(absPnpApiPath); +const absRequire = createRequire(absPnpApiPath); if (existsSync(absPnpApiPath)) { if (!process.versions.pnp) { diff --git a/tgui/.yarn/sdks/typescript/lib/tsserver.js b/tgui/.yarn/sdks/typescript/lib/tsserver.js index 4d90f3879d03..ed800750cc18 100644 --- a/tgui/.yarn/sdks/typescript/lib/tsserver.js +++ b/tgui/.yarn/sdks/typescript/lib/tsserver.js @@ -1,13 +1,20 @@ #!/usr/bin/env node const {existsSync} = require(`fs`); -const {createRequire, createRequireFromPath} = require(`module`); +const {createRequire} = require(`module`); const {resolve} = require(`path`); const relPnpApiPath = "../../../../.pnp.cjs"; const absPnpApiPath = resolve(__dirname, relPnpApiPath); -const absRequire = (createRequire || createRequireFromPath)(absPnpApiPath); +const absRequire = createRequire(absPnpApiPath); + +if (existsSync(absPnpApiPath)) { + if (!process.versions.pnp) { + // Setup the environment to be able to require typescript/lib/tsserver.js + require(absPnpApiPath).setup(); + } +} const moduleWrapper = tsserver => { if (!process.versions.pnp) { @@ -18,6 +25,7 @@ const moduleWrapper = tsserver => { const pnpApi = require(`pnpapi`); const isVirtual = str => str.match(/\/(\$\$virtual|__virtual__)\//); + const isPortal = str => str.startsWith("portal:/"); const normalize = str => str.replace(/\\/g, `/`).replace(/^\/?/, `/`); const dependencyTreeRoots = new Set(pnpApi.getDependencyTreeRoots().map(locator => { @@ -30,7 +38,7 @@ const moduleWrapper = tsserver => { function toEditorPath(str) { // We add the `zip:` prefix to both `.zip/` paths and virtual paths - if (isAbsolute(str) && !str.match(/^\^zip:/) && (str.match(/\.zip\//) || isVirtual(str))) { + if (isAbsolute(str) && !str.match(/^\^?(zip:|\/zip\/)/) && (str.match(/\.zip\//) || isVirtual(str))) { // We also take the opportunity to turn virtual paths into physical ones; // this makes it much easier to work with workspaces that list peer // dependencies, since otherwise Ctrl+Click would bring us to the virtual @@ -44,7 +52,7 @@ const moduleWrapper = tsserver => { const resolved = isVirtual(str) ? pnpApi.resolveVirtual(str) : str; if (resolved) { const locator = pnpApi.findPackageLocator(resolved); - if (locator && dependencyTreeRoots.has(`${locator.name}@${locator.reference}`)) { + if (locator && (dependencyTreeRoots.has(`${locator.name}@${locator.reference}`) || isPortal(locator.reference))) { str = resolved; } } @@ -60,10 +68,34 @@ const moduleWrapper = tsserver => { // // Ref: https://github.com/microsoft/vscode/issues/105014#issuecomment-686760910 // - case `vscode`: { + // 2021-10-08: VSCode changed the format in 1.61. + // Before | ^zip:/c:/foo/bar.zip/package.json + // After | ^/zip//c:/foo/bar.zip/package.json + // + // 2022-04-06: VSCode changed the format in 1.66. + // Before | ^/zip//c:/foo/bar.zip/package.json + // After | ^/zip/c:/foo/bar.zip/package.json + // + // 2022-05-06: VSCode changed the format in 1.68 + // Before | ^/zip/c:/foo/bar.zip/package.json + // After | ^/zip//c:/foo/bar.zip/package.json + // + case `vscode <1.61`: { str = `^zip:${str}`; } break; + case `vscode <1.66`: { + str = `^/zip/${str}`; + } break; + + case `vscode <1.68`: { + str = `^/zip${str}`; + } break; + + case `vscode`: { + str = `^/zip/${str}`; + } break; + // To make "go to definition" work, // We have to resolve the actual file system path from virtual path // and convert scheme to supported by [vim-rzip](https://github.com/lbrayner/vim-rzip) @@ -77,13 +109,15 @@ const moduleWrapper = tsserver => { // everything else is up to neovim case `neovim`: { str = normalize(resolved).replace(/\.zip\//, `.zip::`); - str = `zipfile:${str}`; + str = `zipfile://${str}`; } break; default: { str = `zip:${str}`; } break; } + } else { + str = str.replace(/^\/?/, process.platform === `win32` ? `` : `/`); } } @@ -91,9 +125,28 @@ const moduleWrapper = tsserver => { } function fromEditorPath(str) { - return process.platform === `win32` - ? str.replace(/^\^?zip:\//, ``) - : str.replace(/^\^?zip:/, ``); + switch (hostInfo) { + case `coc-nvim`: { + str = str.replace(/\.zip::/, `.zip/`); + // The path for coc-nvim is in format of //zipfile://.yarn/... + // So in order to convert it back, we use .* to match all the thing + // before `zipfile:` + return process.platform === `win32` + ? str.replace(/^.*zipfile:\//, ``) + : str.replace(/^.*zipfile:/, ``); + } break; + + case `neovim`: { + str = str.replace(/\.zip::/, `.zip/`); + // The path for neovim is in format of zipfile:////.yarn/... + return str.replace(/^zipfile:\/\//, ``); + } break; + + case `vscode`: + default: { + return str.replace(/^\^?(zip:|\/zip(\/ts-nul-authority)?)\/+/, process.platform === `win32` ? `` : `/`) + } break; + } } // Force enable 'allowLocalPluginLoads' @@ -119,8 +172,9 @@ const moduleWrapper = tsserver => { let hostInfo = `unknown`; Object.assign(Session.prototype, { - onMessage(/** @type {string} */ message) { - const parsedMessage = JSON.parse(message) + onMessage(/** @type {string | object} */ message) { + const isStringMessage = typeof message === 'string'; + const parsedMessage = isStringMessage ? JSON.parse(message) : message; if ( parsedMessage != null && @@ -129,11 +183,32 @@ const moduleWrapper = tsserver => { typeof parsedMessage.arguments.hostInfo === `string` ) { hostInfo = parsedMessage.arguments.hostInfo; + if (hostInfo === `vscode` && process.env.VSCODE_IPC_HOOK) { + const [, major, minor] = (process.env.VSCODE_IPC_HOOK.match( + // The RegExp from https://semver.org/ but without the caret at the start + /(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/ + ) ?? []).map(Number) + + if (major === 1) { + if (minor < 61) { + hostInfo += ` <1.61`; + } else if (minor < 66) { + hostInfo += ` <1.66`; + } else if (minor < 68) { + hostInfo += ` <1.68`; + } + } + } } - return originalOnMessage.call(this, JSON.stringify(parsedMessage, (key, value) => { - return typeof value === `string` ? fromEditorPath(value) : value; - })); + const processedMessageJSON = JSON.stringify(parsedMessage, (key, value) => { + return typeof value === 'string' ? fromEditorPath(value) : value; + }); + + return originalOnMessage.call( + this, + isStringMessage ? processedMessageJSON : JSON.parse(processedMessageJSON) + ); }, send(/** @type {any} */ msg) { @@ -146,11 +221,11 @@ const moduleWrapper = tsserver => { return tsserver; }; -if (existsSync(absPnpApiPath)) { - if (!process.versions.pnp) { - // Setup the environment to be able to require typescript/lib/tsserver.js - require(absPnpApiPath).setup(); - } +const [major, minor] = absRequire(`typescript/package.json`).version.split(`.`, 2).map(value => parseInt(value, 10)); +// In TypeScript@>=5.5 the tsserver uses the public TypeScript API so that needs to be patched as well. +// Ref https://github.com/microsoft/TypeScript/pull/55326 +if (major > 5 || (major === 5 && minor >= 5)) { + moduleWrapper(absRequire(`typescript`)); } // Defer to the real typescript/lib/tsserver.js your application uses diff --git a/tgui/.yarn/sdks/typescript/lib/tsserverlibrary.js b/tgui/.yarn/sdks/typescript/lib/tsserverlibrary.js index c3de4ff5d705..4d99766952f5 100644 --- a/tgui/.yarn/sdks/typescript/lib/tsserverlibrary.js +++ b/tgui/.yarn/sdks/typescript/lib/tsserverlibrary.js @@ -1,13 +1,20 @@ #!/usr/bin/env node const {existsSync} = require(`fs`); -const {createRequire, createRequireFromPath} = require(`module`); +const {createRequire} = require(`module`); const {resolve} = require(`path`); const relPnpApiPath = "../../../../.pnp.cjs"; const absPnpApiPath = resolve(__dirname, relPnpApiPath); -const absRequire = (createRequire || createRequireFromPath)(absPnpApiPath); +const absRequire = createRequire(absPnpApiPath); + +if (existsSync(absPnpApiPath)) { + if (!process.versions.pnp) { + // Setup the environment to be able to require typescript/lib/tsserverlibrary.js + require(absPnpApiPath).setup(); + } +} const moduleWrapper = tsserver => { if (!process.versions.pnp) { @@ -18,6 +25,7 @@ const moduleWrapper = tsserver => { const pnpApi = require(`pnpapi`); const isVirtual = str => str.match(/\/(\$\$virtual|__virtual__)\//); + const isPortal = str => str.startsWith("portal:/"); const normalize = str => str.replace(/\\/g, `/`).replace(/^\/?/, `/`); const dependencyTreeRoots = new Set(pnpApi.getDependencyTreeRoots().map(locator => { @@ -30,7 +38,7 @@ const moduleWrapper = tsserver => { function toEditorPath(str) { // We add the `zip:` prefix to both `.zip/` paths and virtual paths - if (isAbsolute(str) && !str.match(/^\^zip:/) && (str.match(/\.zip\//) || isVirtual(str))) { + if (isAbsolute(str) && !str.match(/^\^?(zip:|\/zip\/)/) && (str.match(/\.zip\//) || isVirtual(str))) { // We also take the opportunity to turn virtual paths into physical ones; // this makes it much easier to work with workspaces that list peer // dependencies, since otherwise Ctrl+Click would bring us to the virtual @@ -44,7 +52,7 @@ const moduleWrapper = tsserver => { const resolved = isVirtual(str) ? pnpApi.resolveVirtual(str) : str; if (resolved) { const locator = pnpApi.findPackageLocator(resolved); - if (locator && dependencyTreeRoots.has(`${locator.name}@${locator.reference}`)) { + if (locator && (dependencyTreeRoots.has(`${locator.name}@${locator.reference}`) || isPortal(locator.reference))) { str = resolved; } } @@ -60,10 +68,34 @@ const moduleWrapper = tsserver => { // // Ref: https://github.com/microsoft/vscode/issues/105014#issuecomment-686760910 // - case `vscode`: { + // 2021-10-08: VSCode changed the format in 1.61. + // Before | ^zip:/c:/foo/bar.zip/package.json + // After | ^/zip//c:/foo/bar.zip/package.json + // + // 2022-04-06: VSCode changed the format in 1.66. + // Before | ^/zip//c:/foo/bar.zip/package.json + // After | ^/zip/c:/foo/bar.zip/package.json + // + // 2022-05-06: VSCode changed the format in 1.68 + // Before | ^/zip/c:/foo/bar.zip/package.json + // After | ^/zip//c:/foo/bar.zip/package.json + // + case `vscode <1.61`: { str = `^zip:${str}`; } break; + case `vscode <1.66`: { + str = `^/zip/${str}`; + } break; + + case `vscode <1.68`: { + str = `^/zip${str}`; + } break; + + case `vscode`: { + str = `^/zip/${str}`; + } break; + // To make "go to definition" work, // We have to resolve the actual file system path from virtual path // and convert scheme to supported by [vim-rzip](https://github.com/lbrayner/vim-rzip) @@ -77,13 +109,15 @@ const moduleWrapper = tsserver => { // everything else is up to neovim case `neovim`: { str = normalize(resolved).replace(/\.zip\//, `.zip::`); - str = `zipfile:${str}`; + str = `zipfile://${str}`; } break; default: { str = `zip:${str}`; } break; } + } else { + str = str.replace(/^\/?/, process.platform === `win32` ? `` : `/`); } } @@ -91,9 +125,28 @@ const moduleWrapper = tsserver => { } function fromEditorPath(str) { - return process.platform === `win32` - ? str.replace(/^\^?zip:\//, ``) - : str.replace(/^\^?zip:/, ``); + switch (hostInfo) { + case `coc-nvim`: { + str = str.replace(/\.zip::/, `.zip/`); + // The path for coc-nvim is in format of //zipfile://.yarn/... + // So in order to convert it back, we use .* to match all the thing + // before `zipfile:` + return process.platform === `win32` + ? str.replace(/^.*zipfile:\//, ``) + : str.replace(/^.*zipfile:/, ``); + } break; + + case `neovim`: { + str = str.replace(/\.zip::/, `.zip/`); + // The path for neovim is in format of zipfile:////.yarn/... + return str.replace(/^zipfile:\/\//, ``); + } break; + + case `vscode`: + default: { + return str.replace(/^\^?(zip:|\/zip(\/ts-nul-authority)?)\/+/, process.platform === `win32` ? `` : `/`) + } break; + } } // Force enable 'allowLocalPluginLoads' @@ -119,8 +172,9 @@ const moduleWrapper = tsserver => { let hostInfo = `unknown`; Object.assign(Session.prototype, { - onMessage(/** @type {string} */ message) { - const parsedMessage = JSON.parse(message) + onMessage(/** @type {string | object} */ message) { + const isStringMessage = typeof message === 'string'; + const parsedMessage = isStringMessage ? JSON.parse(message) : message; if ( parsedMessage != null && @@ -129,11 +183,32 @@ const moduleWrapper = tsserver => { typeof parsedMessage.arguments.hostInfo === `string` ) { hostInfo = parsedMessage.arguments.hostInfo; + if (hostInfo === `vscode` && process.env.VSCODE_IPC_HOOK) { + const [, major, minor] = (process.env.VSCODE_IPC_HOOK.match( + // The RegExp from https://semver.org/ but without the caret at the start + /(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/ + ) ?? []).map(Number) + + if (major === 1) { + if (minor < 61) { + hostInfo += ` <1.61`; + } else if (minor < 66) { + hostInfo += ` <1.66`; + } else if (minor < 68) { + hostInfo += ` <1.68`; + } + } + } } - return originalOnMessage.call(this, JSON.stringify(parsedMessage, (key, value) => { - return typeof value === `string` ? fromEditorPath(value) : value; - })); + const processedMessageJSON = JSON.stringify(parsedMessage, (key, value) => { + return typeof value === 'string' ? fromEditorPath(value) : value; + }); + + return originalOnMessage.call( + this, + isStringMessage ? processedMessageJSON : JSON.parse(processedMessageJSON) + ); }, send(/** @type {any} */ msg) { @@ -146,11 +221,11 @@ const moduleWrapper = tsserver => { return tsserver; }; -if (existsSync(absPnpApiPath)) { - if (!process.versions.pnp) { - // Setup the environment to be able to require typescript/lib/tsserverlibrary.js - require(absPnpApiPath).setup(); - } +const [major, minor] = absRequire(`typescript/package.json`).version.split(`.`, 2).map(value => parseInt(value, 10)); +// In TypeScript@>=5.5 the tsserver uses the public TypeScript API so that needs to be patched as well. +// Ref https://github.com/microsoft/TypeScript/pull/55326 +if (major > 5 || (major === 5 && minor >= 5)) { + moduleWrapper(absRequire(`typescript`)); } // Defer to the real typescript/lib/tsserverlibrary.js your application uses diff --git a/tgui/.yarn/sdks/typescript/lib/typescript.js b/tgui/.yarn/sdks/typescript/lib/typescript.js index cbdbf1500fbe..b5f4db25bee6 100644 --- a/tgui/.yarn/sdks/typescript/lib/typescript.js +++ b/tgui/.yarn/sdks/typescript/lib/typescript.js @@ -1,20 +1,20 @@ #!/usr/bin/env node const {existsSync} = require(`fs`); -const {createRequire, createRequireFromPath} = require(`module`); +const {createRequire} = require(`module`); const {resolve} = require(`path`); const relPnpApiPath = "../../../../.pnp.cjs"; const absPnpApiPath = resolve(__dirname, relPnpApiPath); -const absRequire = (createRequire || createRequireFromPath)(absPnpApiPath); +const absRequire = createRequire(absPnpApiPath); if (existsSync(absPnpApiPath)) { if (!process.versions.pnp) { - // Setup the environment to be able to require typescript/lib/typescript.js + // Setup the environment to be able to require typescript require(absPnpApiPath).setup(); } } -// Defer to the real typescript/lib/typescript.js your application uses -module.exports = absRequire(`typescript/lib/typescript.js`); +// Defer to the real typescript your application uses +module.exports = absRequire(`typescript`); diff --git a/tgui/.yarn/sdks/typescript/package.json b/tgui/.yarn/sdks/typescript/package.json index ea85e133e822..9d77f1ac3a17 100644 --- a/tgui/.yarn/sdks/typescript/package.json +++ b/tgui/.yarn/sdks/typescript/package.json @@ -2,5 +2,9 @@ "name": "typescript", "version": "4.3.5-sdk", "main": "./lib/typescript.js", - "type": "commonjs" + "type": "commonjs", + "bin": { + "tsc": "./bin/tsc", + "tsserver": "./bin/tsserver" + } } diff --git a/tgui/.yarnrc.yml b/tgui/.yarnrc.yml index b6387e8e46e8..086484a243a3 100644 --- a/tgui/.yarnrc.yml +++ b/tgui/.yarnrc.yml @@ -8,7 +8,7 @@ logFilters: plugins: - path: .yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs - spec: "@yarnpkg/plugin-interactive-tools" + spec: '@yarnpkg/plugin-interactive-tools' pnpEnableEsmLoader: false diff --git a/tgui/README.md b/tgui/README.md index e87130243429..4a1915d5c897 100644 --- a/tgui/README.md +++ b/tgui/README.md @@ -71,6 +71,7 @@ However, if you want finer control over the installation or build process, you w - `tools/build/build tgui-clean` - Clean up tgui folder. > With Juke Build, you can run multiple targets together, e.g.: +> > ``` > tools/build/build tgui tgui-lint tgui-tsc tgui-test > ``` @@ -137,7 +138,7 @@ Press `F12` or click the green bug to open the KitchenSink interface. This inter playground to test various tgui components. **Layout Debugger.** -Press `F11` to toggle the *layout debugger*. It will show outlines of +Press `F11` to toggle the _layout debugger_. It will show outlines of all tgui elements, which makes it easy to understand how everything comes together, and can reveal certain layout bugs which are not normally visible. diff --git a/tgui/babel.config.js b/tgui/babel.config.js index d8ddb75721db..959dc3be7adb 100644 --- a/tgui/babel.config.js +++ b/tgui/babel.config.js @@ -4,27 +4,36 @@ * @license MIT */ -const createBabelConfig = options => { +const createBabelConfig = (options) => { const { presets = [], plugins = [], removeConsole } = options; return { presets: [ - [require.resolve('@babel/preset-typescript'), { - allowDeclareFields: true, - }], - [require.resolve('@babel/preset-env'), { - modules: 'commonjs', - useBuiltIns: 'entry', - corejs: '3', - spec: false, - loose: true, - targets: [], - }], + [ + require.resolve('@babel/preset-typescript'), + { + allowDeclareFields: true, + }, + ], + [ + require.resolve('@babel/preset-env'), + { + modules: 'commonjs', + useBuiltIns: 'entry', + corejs: '3', + spec: false, + loose: true, + targets: [], + }, + ], ...presets, ].filter(Boolean), plugins: [ - [require.resolve('@babel/plugin-proposal-class-properties'), { - loose: true, - }], + [ + require.resolve('@babel/plugin-proposal-class-properties'), + { + loose: true, + }, + ], require.resolve('@babel/plugin-transform-jscript'), require.resolve('babel-plugin-inferno'), removeConsole && require.resolve('babel-plugin-transform-remove-console'), @@ -34,7 +43,7 @@ const createBabelConfig = options => { }; }; -module.exports = api => { +module.exports = (api) => { api.cache(true); const mode = process.env.NODE_ENV; return createBabelConfig({ mode }); diff --git a/tgui/jest.config.js b/tgui/jest.config.js index e654f0089b84..8b78818004be 100644 --- a/tgui/jest.config.js +++ b/tgui/jest.config.js @@ -4,9 +4,7 @@ module.exports = { '/packages/**/__tests__/*.{js,ts,tsx}', '/packages/**/*.{spec,test}.{js,ts,tsx}', ], - testPathIgnorePatterns: [ - '/packages/tgui-bench', - ], + testPathIgnorePatterns: ['/packages/tgui-bench'], testEnvironment: 'jsdom', testRunner: require.resolve('jest-circus/runner'), transform: { diff --git a/tgui/package.json b/tgui/package.json index e871d874c5d6..86d4b77c2cba 100644 --- a/tgui/package.json +++ b/tgui/package.json @@ -11,12 +11,15 @@ "tgui:analyze": "webpack --analyze", "tgui:dev": "node --experimental-modules packages/tgui-dev-server/index.js", "tgui:lint": "eslint packages --ext .js,.cjs,.ts,.tsx", + "tgui:prettier": "prettier --check .", "tgui:sonar": "eslint packages --ext .js,.cjs,.ts,.tsx -c .eslintrc-sonar.yml", "tgui:tsc": "tsc", "tgui:test": "jest --watch", "tgui:test-simple": "CI=true jest --color", "tgui:test-ci": "CI=true jest --color --collect-coverage", - "tgui:bench": "webpack --env TGUI_BENCH=1 && node packages/tgui-bench/index.js" + "tgui:bench": "webpack --env TGUI_BENCH=1 && node packages/tgui-bench/index.js", + "tgui:prettier-fix": "prettier --write .", + "tgui:eslint-fix": "eslint --fix packages --ext .js,.cjs,.ts,.tsx" }, "dependencies": { "@babel/core": "^7.15.0", @@ -38,6 +41,7 @@ "common": "workspace:*", "css-loader": "^5.2.7", "eslint": "^7.32.0", + "eslint-config-prettier": "^9.1.0", "eslint-plugin-radar": "^0.2.1", "eslint-plugin-react": "^7.24.0", "eslint-plugin-unused-imports": "^1.1.4", @@ -47,6 +51,7 @@ "jest-circus": "^27.0.6", "jsdom": "^16.7.0", "mini-css-extract-plugin": "^1.6.2", + "prettier": "^3.2.5", "sass": "^1.37.5", "sass-loader": "^11.1.1", "style-loader": "^2.0.0", diff --git a/tgui/packages/common/collections.spec.ts b/tgui/packages/common/collections.spec.ts index 58eff7f354c9..ef35a95cb3ea 100644 --- a/tgui/packages/common/collections.spec.ts +++ b/tgui/packages/common/collections.spec.ts @@ -1,20 +1,20 @@ -import { range, zip } from "./collections"; +import { range, zip } from './collections'; // Type assertions, these will lint if the types are wrong. -const _zip1: [string, number] = zip(["a"], [1])[0]; +const _zip1: [string, number] = zip(['a'], [1])[0]; -describe("range", () => { - test("range(0, 5)", () => { +describe('range', () => { + test('range(0, 5)', () => { expect(range(0, 5)).toEqual([0, 1, 2, 3, 4]); }); }); -describe("zip", () => { +describe('zip', () => { test("zip(['a', 'b', 'c'], [1, 2, 3, 4])", () => { - expect(zip(["a", "b", "c"], [1, 2, 3, 4])).toEqual([ - ["a", 1], - ["b", 2], - ["c", 3], + expect(zip(['a', 'b', 'c'], [1, 2, 3, 4])).toEqual([ + ['a', 1], + ['b', 2], + ['c', 3], ]); }); }); diff --git a/tgui/packages/common/collections.ts b/tgui/packages/common/collections.ts index 5ab378070f0b..ab00ad4cacbf 100644 --- a/tgui/packages/common/collections.ts +++ b/tgui/packages/common/collections.ts @@ -14,40 +14,33 @@ * * @returns {any[]} */ -export const filter = (iterateeFn: ( - input: T, - index: number, - collection: T[], -) => boolean) => - (collection: T[]): T[] => { - if (collection === null || collection === undefined) { - return collection; - } - if (Array.isArray(collection)) { - const result: T[] = []; - for (let i = 0; i < collection.length; i++) { - const item = collection[i]; - if (iterateeFn(item, i, collection)) { - result.push(item); - } +export const filter = + (iterateeFn: (input: T, index: number, collection: T[]) => boolean) => + (collection: T[]): T[] => { + if (collection === null || collection === undefined) { + return collection; + } + if (Array.isArray(collection)) { + const result: T[] = []; + for (let i = 0; i < collection.length; i++) { + const item = collection[i]; + if (iterateeFn(item, i, collection)) { + result.push(item); } - return result; } - throw new Error(`filter() can't iterate on type ${typeof collection}`); - }; + return result; + } + throw new Error(`filter() can't iterate on type ${typeof collection}`); + }; type MapFunction = { - (iterateeFn: ( - value: T, - index: number, - collection: T[], - ) => U): (collection: T[]) => U[]; - - (iterateeFn: ( - value: T, - index: K, - collection: Record, - ) => U): (collection: Record) => U[]; + ( + iterateeFn: (value: T, index: number, collection: T[]) => U, + ): (collection: T[]) => U[]; + + ( + iterateeFn: (value: T, index: K, collection: Record) => U, + ): (collection: Record) => U[]; }; /** @@ -58,7 +51,8 @@ type MapFunction = { * If collection is 'null' or 'undefined', it will be returned "as is" * without emitting any errors (which can be useful in some cases). */ -export const map: MapFunction = (iterateeFn) => +export const map: MapFunction = + (iterateeFn) => (collection: T[]): U[] => { if (collection === null || collection === undefined) { return collection; @@ -81,9 +75,10 @@ export const map: MapFunction = (iterateeFn) => * Given a collection, will run each element through an iteratee function. * Will then filter out undefined values. */ -export const filterMap = (collection: T[], iterateeFn: ( - value: T -) => U | undefined): U[] => { +export const filterMap = ( + collection: T[], + iterateeFn: (value: T) => U | undefined, +): U[] => { const finalCollection: U[] = []; for (const value of collection) { @@ -119,22 +114,22 @@ const COMPARATOR = (objA, objB) => { * * Iteratees are called with one argument (value). */ -export const sortBy = ( - ...iterateeFns: ((input: T) => unknown)[] -) => (array: T[]): T[] => { +export const sortBy = + (...iterateeFns: ((input: T) => unknown)[]) => + (array: T[]): T[] => { if (!Array.isArray(array)) { return array; } let length = array.length; // Iterate over the array to collect criteria to sort it by let mappedArray: { - criteria: unknown[], - value: T, + criteria: unknown[]; + value: T; }[] = []; for (let i = 0; i < length; i++) { const value = array[i]; mappedArray.push({ - criteria: iterateeFns.map(fn => fn(value)), + criteria: iterateeFns.map((fn) => fn(value)), value, }); } @@ -163,15 +158,14 @@ export const range = (start: number, end: number): number[] => /** * A fast implementation of reduce. */ -export const reduce = (reducerFn, initialValue) => array => { +export const reduce = (reducerFn, initialValue) => (array) => { const length = array.length; let i; let result; if (initialValue === undefined) { i = 1; result = array[0]; - } - else { + } else { i = 0; result = initialValue; } @@ -192,15 +186,14 @@ export const reduce = (reducerFn, initialValue) => array => { * is determined by the order they occur in the array. The iteratee is * invoked with one argument: value. */ -export const uniqBy = ( - iterateeFn?: (value: T) => unknown -) => (array: T[]): T[] => { +export const uniqBy = + (iterateeFn?: (value: T) => unknown) => + (array: T[]): T[] => { const { length } = array; const result: T[] = []; const seen: unknown[] = iterateeFn ? [] : result; let index = -1; - outer: - while (++index < length) { + outer: while (++index < length) { let value: T | 0 = array[index]; const computed = iterateeFn ? iterateeFn(value) : value; if (computed === computed) { @@ -214,8 +207,7 @@ export const uniqBy = ( seen.push(computed); } result.push(value); - } - else if (!seen.includes(computed)) { + } else if (!seen.includes(computed)) { if (seen !== result) { seen.push(computed); } @@ -261,7 +253,8 @@ export const zip = (...arrays: T): Zip => { * specify how grouped values should be combined. The iteratee is * invoked with the elements of each group. */ -export const zipWith = (iterateeFn: (...values: T[]) => U) => +export const zipWith = + (iterateeFn: (...values: T[]) => U) => (...arrays: T[][]): U[] => { return map((values: T[]) => iterateeFn(...values))(zip(...arrays)); }; @@ -301,9 +294,9 @@ const binarySearch = ( return compare > insertingKey ? middle : middle + 1; }; -export const binaryInsertWith = (getKey: (value: T) => U): - ((collection: readonly T[], value: T) => T[]) => -{ +export const binaryInsertWith = ( + getKey: (value: T) => U, +): ((collection: readonly T[], value: T) => T[]) => { return (collection, value) => { const copy = [...collection]; copy.splice(binarySearch(getKey, collection, value), 0, value); diff --git a/tgui/packages/common/color.js b/tgui/packages/common/color.js index 2aadae8d6bdf..fffd452ddb83 100644 --- a/tgui/packages/common/color.js +++ b/tgui/packages/common/color.js @@ -27,23 +27,23 @@ export class Color { /** * Creates a color from the CSS hex color notation. */ -Color.fromHex = hex => ( +Color.fromHex = (hex) => new Color( parseInt(hex.substr(1, 2), 16), parseInt(hex.substr(3, 2), 16), - parseInt(hex.substr(5, 2), 16)) -); + parseInt(hex.substr(5, 2), 16), + ); /** * Linear interpolation of two colors. */ -Color.lerp = (c1, c2, n) => ( +Color.lerp = (c1, c2, n) => new Color( (c2.r - c1.r) * n + c1.r, (c2.g - c1.g) * n + c1.g, (c2.b - c1.b) * n + c1.b, - (c2.a - c1.a) * n + c1.a) -); + (c2.a - c1.a) * n + c1.a, + ); /** * Loops up the color in the provided list of colors diff --git a/tgui/packages/common/events.js b/tgui/packages/common/events.js index 6d590a34453b..7eeff511aa56 100644 --- a/tgui/packages/common/events.js +++ b/tgui/packages/common/events.js @@ -19,10 +19,9 @@ export class EventEmitter { if (!listeners) { throw new Error(`There is no listeners for "${name}"`); } - this.listeners[name] = listeners - .filter(existingListener => { - return existingListener !== listener; - }); + this.listeners[name] = listeners.filter((existingListener) => { + return existingListener !== listener; + }); } emit(name, ...params) { diff --git a/tgui/packages/common/fp.js b/tgui/packages/common/fp.js index 7aa00a00f3ee..b8da91e52f09 100644 --- a/tgui/packages/common/fp.js +++ b/tgui/packages/common/fp.js @@ -9,19 +9,20 @@ * functions, where each successive invocation is supplied the return * value of the previous. */ -export const flow = (...funcs) => (input, ...rest) => { - let output = input; - for (let func of funcs) { - // Recurse into the array of functions - if (Array.isArray(func)) { - output = flow(...func)(output, ...rest); +export const flow = + (...funcs) => + (input, ...rest) => { + let output = input; + for (let func of funcs) { + // Recurse into the array of functions + if (Array.isArray(func)) { + output = flow(...func)(output, ...rest); + } else if (func) { + output = func(output, ...rest); + } } - else if (func) { - output = func(output, ...rest); - } - } - return output; -}; + return output; + }; /** * Composes single-argument functions from right to left. @@ -37,11 +38,14 @@ export const flow = (...funcs) => (input, ...rest) => { */ export const compose = (...funcs) => { if (funcs.length === 0) { - return arg => arg; + return (arg) => arg; } if (funcs.length === 1) { return funcs[0]; } - return funcs.reduce((a, b) => (value, ...rest) => - a(b(value, ...rest), ...rest)); + return funcs.reduce( + (a, b) => + (value, ...rest) => + a(b(value, ...rest), ...rest), + ); }; diff --git a/tgui/packages/common/math.ts b/tgui/packages/common/math.ts index 97e6b60b2ed4..9dc1d6556936 100644 --- a/tgui/packages/common/math.ts +++ b/tgui/packages/common/math.ts @@ -14,7 +14,7 @@ export const clamp = (value, min, max) => { /** * Limits a number between 0 and 1. */ -export const clamp01 = value => { +export const clamp01 = (value) => { return value < 0 ? 0 : value > 1 ? 1 : value; }; @@ -69,9 +69,7 @@ export const toFixed = (value, fractionDigits = 0) => { * Range is an array of two numbers, for example: [0, 15]. */ export const inRange = (value, range) => { - return range - && value >= range[0] - && value <= range[1]; + return range && value >= range[0] && value <= range[1]; }; /** @@ -92,7 +90,7 @@ export const keyOfMatchingRange = (value, ranges) => { /** * Get number of digits following the decimal point in a number */ -export const numberOfDecimalDigits = value => { +export const numberOfDecimalDigits = (value) => { if (Math.floor(value) !== value) { return value.toString().split('.')[1].length || 0; } diff --git a/tgui/packages/common/perf.js b/tgui/packages/common/perf.js index 8414971f93b0..c2d6cb27db15 100644 --- a/tgui/packages/common/perf.js +++ b/tgui/packages/common/perf.js @@ -48,10 +48,15 @@ const measure = (markerNameA, markerNameB) => { } }; -const formatDuration = duration => { +const formatDuration = (duration) => { const durationInFrames = duration / FRAME_DURATION; - return duration.toFixed(duration < 10 ? 1 : 0) + 'ms ' - + '(' + durationInFrames.toFixed(2) + ' frames)'; + return ( + duration.toFixed(duration < 10 ? 1 : 0) + + 'ms ' + + '(' + + durationInFrames.toFixed(2) + + ' frames)' + ); }; export const perf = { diff --git a/tgui/packages/common/react.ts b/tgui/packages/common/react.ts index c8a08f04934b..6789bb4edc65 100644 --- a/tgui/packages/common/react.ts +++ b/tgui/packages/common/react.ts @@ -24,7 +24,7 @@ export const classes = (classNames: (string | BooleanLike)[]) => { */ export const normalizeChildren = (children: T | T[]) => { if (Array.isArray(children)) { - return children.flat().filter(value => value) as T[]; + return children.flat().filter((value) => value) as T[]; } if (typeof children === 'object') { return [children]; @@ -64,9 +64,7 @@ export const pureComponentHooks = { * A helper to determine whether the object is renderable by React. */ export const canRender = (value: unknown) => { - return value !== undefined - && value !== null - && typeof value !== 'boolean'; + return value !== undefined && value !== null && typeof value !== 'boolean'; }; /** diff --git a/tgui/packages/common/redux.js b/tgui/packages/common/redux.js index ebed11f166b2..0c2dd6b670cb 100644 --- a/tgui/packages/common/redux.js +++ b/tgui/packages/common/redux.js @@ -20,11 +20,11 @@ export const createStore = (reducer, enhancer) => { const getState = () => currentState; - const subscribe = listener => { + const subscribe = (listener) => { listeners.push(listener); }; - const dispatch = action => { + const dispatch = (action) => { currentState = reducer(currentState, action); for (let i = 0; i < listeners.length; i++) { listeners[i](); @@ -49,27 +49,29 @@ export const createStore = (reducer, enhancer) => { * actions. */ export const applyMiddleware = (...middlewares) => { - return createStore => (reducer, ...args) => { - const store = createStore(reducer, ...args); - - let dispatch = () => { - throw new Error( - 'Dispatching while constructing your middleware is not allowed.'); - }; - - const storeApi = { - getState: store.getState, - dispatch: (action, ...args) => dispatch(action, ...args), - }; - - const chain = middlewares.map(middleware => middleware(storeApi)); - dispatch = compose(...chain)(store.dispatch); - - return { - ...store, - dispatch, + return (createStore) => + (reducer, ...args) => { + const store = createStore(reducer, ...args); + + let dispatch = () => { + throw new Error( + 'Dispatching while constructing your middleware is not allowed.', + ); + }; + + const storeApi = { + getState: store.getState, + dispatch: (action, ...args) => dispatch(action, ...args), + }; + + const chain = middlewares.map((middleware) => middleware(storeApi)); + dispatch = compose(...chain)(store.dispatch); + + return { + ...store, + dispatch, + }; }; - }; }; /** @@ -80,7 +82,7 @@ export const applyMiddleware = (...middlewares) => { * in the state that are not present in the reducers object. This function * is also more flexible than the redux counterpart. */ -export const combineReducers = reducersObj => { +export const combineReducers = (reducersObj) => { const keys = Object.keys(reducersObj); let hasChanged = false; return (prevState = {}, action) => { @@ -94,9 +96,7 @@ export const combineReducers = reducersObj => { nextState[key] = nextDomainState; } } - return hasChanged - ? nextState - : prevState; + return hasChanged ? nextState : prevState; }; }; @@ -136,15 +136,14 @@ export const createAction = (type, prepare = null) => { }; actionCreator.toString = () => '' + type; actionCreator.type = type; - actionCreator.match = action => action.type === type; + actionCreator.match = (action) => action.type === type; return actionCreator; }; - // Implementation specific // -------------------------------------------------------- -export const useDispatch = context => { +export const useDispatch = (context) => { return context.store.dispatch; }; diff --git a/tgui/packages/common/storage.js b/tgui/packages/common/storage.js index dd137dd5d78c..af735769c140 100644 --- a/tgui/packages/common/storage.js +++ b/tgui/packages/common/storage.js @@ -17,11 +17,10 @@ const INDEXED_DB_STORE_NAME = 'daedalus-storage-v1'; const READ_ONLY = 'readonly'; const READ_WRITE = 'readwrite'; -const testGeneric = testFn => () => { +const testGeneric = (testFn) => () => { try { return Boolean(testFn()); - } - catch { + } catch { return false; } }; @@ -29,14 +28,15 @@ const testGeneric = testFn => () => { // Localstorage can sometimes throw an error, even if DOM storage is not // disabled in IE11 settings. // See: https://superuser.com/questions/1080011 -const testLocalStorage = testGeneric(() => ( - window.localStorage && window.localStorage.getItem -)); +const testLocalStorage = testGeneric( + () => window.localStorage && window.localStorage.getItem, +); -const testIndexedDb = testGeneric(() => ( - (window.indexedDB || window.msIndexedDB) - && (window.IDBTransaction || window.msIDBTransaction) -)); +const testIndexedDb = testGeneric( + () => + (window.indexedDB || window.msIndexedDB) && + (window.IDBTransaction || window.msIDBTransaction), +); class MemoryBackend { constructor() { @@ -96,8 +96,7 @@ class IndexedDbBackend { req.onupgradeneeded = () => { try { req.result.createObjectStore(INDEXED_DB_STORE_NAME); - } - catch (err) { + } catch (err) { reject(new Error('Failed to upgrade IDB: ' + req.error)); } }; @@ -109,9 +108,11 @@ class IndexedDbBackend { } getStore(mode) { - return this.dbPromise.then(db => db - .transaction(INDEXED_DB_STORE_NAME, mode) - .objectStore(INDEXED_DB_STORE_NAME)); + return this.dbPromise.then((db) => + db + .transaction(INDEXED_DB_STORE_NAME, mode) + .objectStore(INDEXED_DB_STORE_NAME), + ); } async get(key) { @@ -161,8 +162,7 @@ class StorageProxy { const backend = new IndexedDbBackend(); await backend.dbPromise; return backend; - } - catch {} + } catch {} } if (testLocalStorage()) { return new LocalStorageBackend(); diff --git a/tgui/packages/common/string.babel-plugin.cjs b/tgui/packages/common/string.babel-plugin.cjs index 68295aefcf84..97ca67c6ea4c 100644 --- a/tgui/packages/common/string.babel-plugin.cjs +++ b/tgui/packages/common/string.babel-plugin.cjs @@ -19,7 +19,7 @@ /** * Removes excess whitespace and indentation from the string. */ -const multiline = str => { +const multiline = (str) => { const lines = str.split('\n'); // Determine base indentation let minIndent; @@ -40,15 +40,15 @@ const multiline = str => { // Remove this base indentation and trim the resulting string // from both ends. return lines - .map(line => line.substr(minIndent).trimRight()) + .map((line) => line.substr(minIndent).trimRight()) .join('\n') .trim(); }; -const StringPlugin = ref => { +const StringPlugin = (ref) => { return { visitor: { - TaggedTemplateExpression: path => { + TaggedTemplateExpression: (path) => { if (path.node.tag.name === 'multiline') { const { quasi } = path.node; if (quasi.expressions.length > 0) { diff --git a/tgui/packages/common/string.js b/tgui/packages/common/string.js index 16a0921a2559..7ed73a0b2860 100644 --- a/tgui/packages/common/string.js +++ b/tgui/packages/common/string.js @@ -7,7 +7,7 @@ /** * Removes excess whitespace and indentation from the string. */ -export const multiline = str => { +export const multiline = (str) => { if (Array.isArray(str)) { // Small stub to allow usage as a template tag return multiline(str.join('')); @@ -32,7 +32,7 @@ export const multiline = str => { // Remove this base indentation and trim the resulting string // from both ends. return lines - .map(line => line.substr(minIndent).trimRight()) + .map((line) => line.substr(minIndent).trimRight()) .join('\n') .trim(); }; @@ -44,12 +44,12 @@ export const multiline = str => { * * Example: createGlobPattern('*@domain')('user@domain') === true */ -export const createGlobPattern = pattern => { - const escapeString = str => str.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&'); - const regex = new RegExp('^' - + pattern.split(/\*+/).map(escapeString).join('.*') - + '$'); - return str => regex.test(str); +export const createGlobPattern = (pattern) => { + const escapeString = (str) => str.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&'); + const regex = new RegExp( + '^' + pattern.split(/\*+/).map(escapeString).join('.*') + '$', + ); + return (str) => regex.test(str); }; /** @@ -64,7 +64,7 @@ export const createGlobPattern = pattern => { */ export const createSearch = (searchText, stringifier) => { const preparedSearchText = searchText.toLowerCase().trim(); - return obj => { + return (obj) => { if (!preparedSearchText) { return true; } @@ -72,13 +72,11 @@ export const createSearch = (searchText, stringifier) => { if (!str) { return false; } - return str - .toLowerCase() - .includes(preparedSearchText); + return str.toLowerCase().includes(preparedSearchText); }; }; -export const capitalize = str => { +export const capitalize = (str) => { // Handle array if (Array.isArray(str)) { return str.map(capitalize); @@ -87,7 +85,7 @@ export const capitalize = str => { return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase(); }; -export const toTitleCase = str => { +export const toTitleCase = (str) => { // Handle array if (Array.isArray(str)) { return str.map(toTitleCase); @@ -99,19 +97,38 @@ export const toTitleCase = str => { // Handle string const WORDS_UPPER = ['Id', 'Tv']; const WORDS_LOWER = [ - 'A', 'An', 'And', 'As', 'At', 'But', 'By', 'For', 'For', 'From', 'In', - 'Into', 'Near', 'Nor', 'Of', 'On', 'Onto', 'Or', 'The', 'To', 'With', + 'A', + 'An', + 'And', + 'As', + 'At', + 'But', + 'By', + 'For', + 'For', + 'From', + 'In', + 'Into', + 'Near', + 'Nor', + 'Of', + 'On', + 'Onto', + 'Or', + 'The', + 'To', + 'With', ]; - let currentStr = str.replace(/([^\W_]+[^\s-]*) */g, str => { + let currentStr = str.replace(/([^\W_]+[^\s-]*) */g, (str) => { return str.charAt(0).toUpperCase() + str.substr(1).toLowerCase(); }); for (let word of WORDS_LOWER) { const regex = new RegExp('\\s' + word + '\\s', 'g'); - currentStr = currentStr.replace(regex, str => str.toLowerCase()); + currentStr = currentStr.replace(regex, (str) => str.toLowerCase()); } for (let word of WORDS_UPPER) { const regex = new RegExp('\\b' + word + '\\b', 'g'); - currentStr = currentStr.replace(regex, str => str.toLowerCase()); + currentStr = currentStr.replace(regex, (str) => str.toLowerCase()); } return currentStr; }; @@ -122,7 +139,7 @@ export const toTitleCase = str => { * @param {String} str Encoded HTML string * @return {String} Decoded HTML string */ -export const decodeHtmlEntities = str => { +export const decodeHtmlEntities = (str) => { if (!str) { return str; } @@ -133,30 +150,32 @@ export const decodeHtmlEntities = str => { quot: '"', lt: '<', gt: '>', - apos: '\'', + apos: "'", }; - return str - // Newline tags - .replace(/
/gi, '\n') - .replace(/<\/?[a-z0-9-_]+[^>]*>/gi, '') - // Basic entities - .replace(translate_re, (match, entity) => translate[entity]) - // Decimal entities - .replace(/&#?([0-9]+);/gi, (match, numStr) => { - const num = parseInt(numStr, 10); - return String.fromCharCode(num); - }) - // Hex entities - .replace(/&#x?([0-9a-f]+);/gi, (match, numStr) => { - const num = parseInt(numStr, 16); - return String.fromCharCode(num); - }); + return ( + str + // Newline tags + .replace(/
/gi, '\n') + .replace(/<\/?[a-z0-9-_]+[^>]*>/gi, '') + // Basic entities + .replace(translate_re, (match, entity) => translate[entity]) + // Decimal entities + .replace(/&#?([0-9]+);/gi, (match, numStr) => { + const num = parseInt(numStr, 10); + return String.fromCharCode(num); + }) + // Hex entities + .replace(/&#x?([0-9a-f]+);/gi, (match, numStr) => { + const num = parseInt(numStr, 16); + return String.fromCharCode(num); + }) + ); }; /** * Converts an object into a query string, */ -export const buildQueryString = obj => Object.keys(obj) - .map(key => encodeURIComponent(key) - + '=' + encodeURIComponent(obj[key])) - .join('&'); +export const buildQueryString = (obj) => + Object.keys(obj) + .map((key) => encodeURIComponent(key) + '=' + encodeURIComponent(obj[key])) + .join('&'); diff --git a/tgui/packages/common/timer.js b/tgui/packages/common/timer.js index 1177071b9c62..0b1c68199e9f 100644 --- a/tgui/packages/common/timer.js +++ b/tgui/packages/common/timer.js @@ -33,6 +33,5 @@ export const debounce = (fn, time, immediate = false) => { * * @param {number} time */ -export const sleep = time => ( - new Promise(resolve => setTimeout(resolve, time)) -); +export const sleep = (time) => + new Promise((resolve) => setTimeout(resolve, time)); diff --git a/tgui/packages/common/types.ts b/tgui/packages/common/types.ts index a92ac122d9fe..e68aadbdb11c 100644 --- a/tgui/packages/common/types.ts +++ b/tgui/packages/common/types.ts @@ -1,5 +1,8 @@ /** * Returns the arguments of a function F as an array. */ -export type ArgumentsOf - = F extends (...args: infer A) => unknown ? A : never; +export type ArgumentsOf = F extends ( + ...args: infer A +) => unknown + ? A + : never; diff --git a/tgui/packages/common/uuid.js b/tgui/packages/common/uuid.js index 7721af64949b..f2eb4bb98f4e 100644 --- a/tgui/packages/common/uuid.js +++ b/tgui/packages/common/uuid.js @@ -11,9 +11,9 @@ */ export const createUuid = () => { let d = new Date().getTime(); - return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => { + return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => { const r = (d + Math.random() * 16) % 16 | 0; d = Math.floor(d / 16); - return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16); + return (c === 'x' ? r : (r & 0x3) | 0x8).toString(16); }); }; diff --git a/tgui/packages/common/vector.js b/tgui/packages/common/vector.js index c3ac350a4e8e..b1f85f7429db 100644 --- a/tgui/packages/common/vector.js +++ b/tgui/packages/common/vector.js @@ -32,17 +32,17 @@ export const vecDivide = (...vecs) => { }; export const vecScale = (vec, n) => { - return map(x => x * n)(vec); + return map((x) => x * n)(vec); }; -export const vecInverse = vec => { - return map(x => -x)(vec); +export const vecInverse = (vec) => { + return map((x) => -x)(vec); }; -export const vecLength = vec => { +export const vecLength = (vec) => { return Math.sqrt(reduce(ADD)(zipWith(MUL)(vec, vec))); }; -export const vecNormalize = vec => { +export const vecNormalize = (vec) => { return vecDivide(vec, vecLength(vec)); }; diff --git a/tgui/packages/tgfont/icons/ATTRIBUTIONS.md b/tgui/packages/tgfont/icons/ATTRIBUTIONS.md index 2f218388d364..0491b90e726e 100644 --- a/tgui/packages/tgfont/icons/ATTRIBUTIONS.md +++ b/tgui/packages/tgfont/icons/ATTRIBUTIONS.md @@ -1,6 +1,8 @@ bad-touch.svg contains: + - hug by Phạm Thanh Lộc from the Noun Project - Fight by Rudez Studio from the Noun Project prosthetic-leg.svg contains: + - prosthetic leg by Gan Khoon Lay from the Noun Project diff --git a/tgui/packages/tgfont/mkdist.cjs b/tgui/packages/tgfont/mkdist.cjs index 5c628becf992..85634bd265d9 100644 --- a/tgui/packages/tgfont/mkdist.cjs +++ b/tgui/packages/tgfont/mkdist.cjs @@ -10,5 +10,4 @@ process.chdir(__dirname); // Silently make a dist folder try { require('fs').mkdirSync('dist'); -} -catch (err) {} +} catch (err) {} diff --git a/tgui/packages/tgui-bench/entrypoint.tsx b/tgui/packages/tgui-bench/entrypoint.tsx index d72aa60a667e..377848fe3ae0 100644 --- a/tgui/packages/tgui-bench/entrypoint.tsx +++ b/tgui/packages/tgui-bench/entrypoint.tsx @@ -62,8 +62,7 @@ const setupApp = async () => { } suite.run(); }); - } - catch (error) { + } catch (error) { sendMessage({ type: 'error', error }); } } diff --git a/tgui/packages/tgui-bench/index.js b/tgui/packages/tgui-bench/index.js index ac3d8c9cce09..9f6aee20996d 100644 --- a/tgui/packages/tgui-bench/index.js +++ b/tgui/packages/tgui-bench/index.js @@ -27,7 +27,8 @@ const setup = async () => { assets += `\n`; const publicDir = path.resolve(__dirname, '../../public'); - const page = fs.readFileSync(path.join(publicDir, 'tgui.html'), 'utf-8') + const page = fs + .readFileSync(path.join(publicDir, 'tgui.html'), 'utf-8') .replace('\n', assets); server.register(require('fastify-static'), { @@ -67,8 +68,7 @@ const setup = async () => { try { await server.listen(3002, '0.0.0.0'); - } - catch (err) { + } catch (err) { console.error(err); process.exit(1); } diff --git a/tgui/packages/tgui-bench/lib/benchmark.d.ts b/tgui/packages/tgui-bench/lib/benchmark.d.ts index 7f3310005f77..3eac568d4184 100644 --- a/tgui/packages/tgui-bench/lib/benchmark.d.ts +++ b/tgui/packages/tgui-bench/lib/benchmark.d.ts @@ -27,7 +27,7 @@ declare class Benchmark { static reduce( arr: T[], callback: (accumulator: K, value: T) => K, - thisArg?: any + thisArg?: any, ): K; static options: Benchmark.Options; diff --git a/tgui/packages/tgui-bench/lib/benchmark.js b/tgui/packages/tgui-bench/lib/benchmark.js index 1e76cec70870..335934833024 100644 --- a/tgui/packages/tgui-bench/lib/benchmark.js +++ b/tgui/packages/tgui-bench/lib/benchmark.js @@ -7,7 +7,7 @@ * Manually stripped from useless junk by /tg/station13 maintainers. * Available under MIT license */ -module.exports = (function() { +module.exports = function () { 'use strict'; /** Used as a safe reference for `undefined` in pre ES5 environments. */ @@ -15,8 +15,8 @@ module.exports = (function() { /** Used to determine if values are of the language type Object. */ var objectTypes = { - 'function': true, - 'object': true + function: true, + object: true, }; /** Used as a reference to the global object. */ @@ -36,18 +36,33 @@ module.exports = (function() { /** Used to assign default `context` object properties. */ var contextProps = [ - 'Array', 'Date', 'Function', 'Math', 'Object', 'RegExp', 'String', '_', - 'clearTimeout', 'chrome', 'chromium', 'document', 'navigator', 'phantom', - 'platform', 'process', 'runtime', 'setTimeout' + 'Array', + 'Date', + 'Function', + 'Math', + 'Object', + 'RegExp', + 'String', + '_', + 'clearTimeout', + 'chrome', + 'chromium', + 'document', + 'navigator', + 'phantom', + 'platform', + 'process', + 'runtime', + 'setTimeout', ]; /** Used to avoid hz of Infinity. */ var divisors = { - '1': 4096, - '2': 512, - '3': 64, - '4': 8, - '5': 0 + 1: 4096, + 2: 512, + 3: 64, + 4: 8, + 5: 0, }; /** @@ -55,12 +70,37 @@ module.exports = (function() { * For more info see http://www.itl.nist.gov/div898/handbook/eda/section3/eda3672.htm. */ var tTable = { - '1': 12.706, '2': 4.303, '3': 3.182, '4': 2.776, '5': 2.571, '6': 2.447, - '7': 2.365, '8': 2.306, '9': 2.262, '10': 2.228, '11': 2.201, '12': 2.179, - '13': 2.16, '14': 2.145, '15': 2.131, '16': 2.12, '17': 2.11, '18': 2.101, - '19': 2.093, '20': 2.086, '21': 2.08, '22': 2.074, '23': 2.069, '24': 2.064, - '25': 2.06, '26': 2.056, '27': 2.052, '28': 2.048, '29': 2.045, '30': 2.042, - 'infinity': 1.96 + 1: 12.706, + 2: 4.303, + 3: 3.182, + 4: 2.776, + 5: 2.571, + 6: 2.447, + 7: 2.365, + 8: 2.306, + 9: 2.262, + 10: 2.228, + 11: 2.201, + 12: 2.179, + 13: 2.16, + 14: 2.145, + 15: 2.131, + 16: 2.12, + 17: 2.11, + 18: 2.101, + 19: 2.093, + 20: 2.086, + 21: 2.08, + 22: 2.074, + 23: 2.069, + 24: 2.064, + 25: 2.06, + 26: 2.056, + 27: 2.052, + 28: 2.048, + 29: 2.045, + 30: 2.042, + infinity: 1.96, }; /** @@ -68,32 +108,64 @@ module.exports = (function() { * For more info see http://www.saburchill.com/IBbiology/stats/003.html. */ var uTable = { - '5': [0, 1, 2], - '6': [1, 2, 3, 5], - '7': [1, 3, 5, 6, 8], - '8': [2, 4, 6, 8, 10, 13], - '9': [2, 4, 7, 10, 12, 15, 17], - '10': [3, 5, 8, 11, 14, 17, 20, 23], - '11': [3, 6, 9, 13, 16, 19, 23, 26, 30], - '12': [4, 7, 11, 14, 18, 22, 26, 29, 33, 37], - '13': [4, 8, 12, 16, 20, 24, 28, 33, 37, 41, 45], - '14': [5, 9, 13, 17, 22, 26, 31, 36, 40, 45, 50, 55], - '15': [5, 10, 14, 19, 24, 29, 34, 39, 44, 49, 54, 59, 64], - '16': [6, 11, 15, 21, 26, 31, 37, 42, 47, 53, 59, 64, 70, 75], - '17': [6, 11, 17, 22, 28, 34, 39, 45, 51, 57, 63, 67, 75, 81, 87], - '18': [7, 12, 18, 24, 30, 36, 42, 48, 55, 61, 67, 74, 80, 86, 93, 99], - '19': [7, 13, 19, 25, 32, 38, 45, 52, 58, 65, 72, 78, 85, 92, 99, 106, 113], - '20': [8, 14, 20, 27, 34, 41, 48, 55, 62, 69, 76, 83, 90, 98, 105, 112, 119, 127], - '21': [8, 15, 22, 29, 36, 43, 50, 58, 65, 73, 80, 88, 96, 103, 111, 119, 126, 134, 142], - '22': [9, 16, 23, 30, 38, 45, 53, 61, 69, 77, 85, 93, 101, 109, 117, 125, 133, 141, 150, 158], - '23': [9, 17, 24, 32, 40, 48, 56, 64, 73, 81, 89, 98, 106, 115, 123, 132, 140, 149, 157, 166, 175], - '24': [10, 17, 25, 33, 42, 50, 59, 67, 76, 85, 94, 102, 111, 120, 129, 138, 147, 156, 165, 174, 183, 192], - '25': [10, 18, 27, 35, 44, 53, 62, 71, 80, 89, 98, 107, 117, 126, 135, 145, 154, 163, 173, 182, 192, 201, 211], - '26': [11, 19, 28, 37, 46, 55, 64, 74, 83, 93, 102, 112, 122, 132, 141, 151, 161, 171, 181, 191, 200, 210, 220, 230], - '27': [11, 20, 29, 38, 48, 57, 67, 77, 87, 97, 107, 118, 125, 138, 147, 158, 168, 178, 188, 199, 209, 219, 230, 240, 250], - '28': [12, 21, 30, 40, 50, 60, 70, 80, 90, 101, 111, 122, 132, 143, 154, 164, 175, 186, 196, 207, 218, 228, 239, 250, 261, 272], - '29': [13, 22, 32, 42, 52, 62, 73, 83, 94, 105, 116, 127, 138, 149, 160, 171, 182, 193, 204, 215, 226, 238, 249, 260, 271, 282, 294], - '30': [13, 23, 33, 43, 54, 65, 76, 87, 98, 109, 120, 131, 143, 154, 166, 177, 189, 200, 212, 223, 235, 247, 258, 270, 282, 293, 305, 317] + 5: [0, 1, 2], + 6: [1, 2, 3, 5], + 7: [1, 3, 5, 6, 8], + 8: [2, 4, 6, 8, 10, 13], + 9: [2, 4, 7, 10, 12, 15, 17], + 10: [3, 5, 8, 11, 14, 17, 20, 23], + 11: [3, 6, 9, 13, 16, 19, 23, 26, 30], + 12: [4, 7, 11, 14, 18, 22, 26, 29, 33, 37], + 13: [4, 8, 12, 16, 20, 24, 28, 33, 37, 41, 45], + 14: [5, 9, 13, 17, 22, 26, 31, 36, 40, 45, 50, 55], + 15: [5, 10, 14, 19, 24, 29, 34, 39, 44, 49, 54, 59, 64], + 16: [6, 11, 15, 21, 26, 31, 37, 42, 47, 53, 59, 64, 70, 75], + 17: [6, 11, 17, 22, 28, 34, 39, 45, 51, 57, 63, 67, 75, 81, 87], + 18: [7, 12, 18, 24, 30, 36, 42, 48, 55, 61, 67, 74, 80, 86, 93, 99], + 19: [7, 13, 19, 25, 32, 38, 45, 52, 58, 65, 72, 78, 85, 92, 99, 106, 113], + 20: [ + 8, 14, 20, 27, 34, 41, 48, 55, 62, 69, 76, 83, 90, 98, 105, 112, 119, 127, + ], + 21: [ + 8, 15, 22, 29, 36, 43, 50, 58, 65, 73, 80, 88, 96, 103, 111, 119, 126, + 134, 142, + ], + 22: [ + 9, 16, 23, 30, 38, 45, 53, 61, 69, 77, 85, 93, 101, 109, 117, 125, 133, + 141, 150, 158, + ], + 23: [ + 9, 17, 24, 32, 40, 48, 56, 64, 73, 81, 89, 98, 106, 115, 123, 132, 140, + 149, 157, 166, 175, + ], + 24: [ + 10, 17, 25, 33, 42, 50, 59, 67, 76, 85, 94, 102, 111, 120, 129, 138, 147, + 156, 165, 174, 183, 192, + ], + 25: [ + 10, 18, 27, 35, 44, 53, 62, 71, 80, 89, 98, 107, 117, 126, 135, 145, 154, + 163, 173, 182, 192, 201, 211, + ], + 26: [ + 11, 19, 28, 37, 46, 55, 64, 74, 83, 93, 102, 112, 122, 132, 141, 151, 161, + 171, 181, 191, 200, 210, 220, 230, + ], + 27: [ + 11, 20, 29, 38, 48, 57, 67, 77, 87, 97, 107, 118, 125, 138, 147, 158, 168, + 178, 188, 199, 209, 219, 230, 240, 250, + ], + 28: [ + 12, 21, 30, 40, 50, 60, 70, 80, 90, 101, 111, 122, 132, 143, 154, 164, + 175, 186, 196, 207, 218, 228, 239, 250, 261, 272, + ], + 29: [ + 13, 22, 32, 42, 52, 62, 73, 83, 94, 105, 116, 127, 138, 149, 160, 171, + 182, 193, 204, 215, 226, 238, 249, 260, 271, 282, 294, + ], + 30: [ + 13, 23, 33, 43, 54, 65, 76, 87, 98, 109, 120, 131, 143, 154, 166, 177, + 189, 200, 212, 223, 235, 247, 258, 270, 282, 293, 305, 317, + ], }; /*--------------------------------------------------------------------------*/ @@ -108,7 +180,7 @@ module.exports = (function() { */ function runInContext(context) { // Exit early if unable to acquire lodash. - var _ = context && context._ || require('lodash') || root._; + var _ = (context && context._) || require('lodash') || root._; if (!_) { Benchmark.runInContext = runInContext; return Benchmark; @@ -117,36 +189,38 @@ module.exports = (function() { // after built-in constructors like `Object`, for the creation of literals. // ES5 clears this up by stating that literals must use built-in constructors. // See http://es5.github.io/#x11.1.5. - context = context ? _.defaults(root.Object(), context, _.pick(root, contextProps)) : root; + context = context + ? _.defaults(root.Object(), context, _.pick(root, contextProps)) + : root; /** Native constructor references. */ var Array = context.Array, - Date = context.Date, - Function = context.Function, - Math = context.Math, - Object = context.Object, - RegExp = context.RegExp, - String = context.String; + Date = context.Date, + Function = context.Function, + Math = context.Math, + Object = context.Object, + RegExp = context.RegExp, + String = context.String; /** Used for `Array` and `Object` method references. */ var arrayRef = [], - objectProto = Object.prototype; + objectProto = Object.prototype; /** Native method shortcuts. */ var abs = Math.abs, - clearTimeout = context.clearTimeout, - floor = Math.floor, - log = Math.log, - max = Math.max, - min = Math.min, - pow = Math.pow, - push = arrayRef.push, - setTimeout = context.setTimeout, - shift = arrayRef.shift, - slice = arrayRef.slice, - sqrt = Math.sqrt, - toString = objectProto.toString, - unshift = arrayRef.unshift; + clearTimeout = context.clearTimeout, + floor = Math.floor, + log = Math.log, + max = Math.max, + min = Math.min, + pow = Math.pow, + push = arrayRef.push, + setTimeout = context.setTimeout, + shift = arrayRef.shift, + slice = arrayRef.slice, + sqrt = Math.sqrt, + toString = objectProto.toString, + unshift = arrayRef.unshift; /** Detect DOM document object. */ var doc = isHostType(context, 'document') && context.document; @@ -172,15 +246,17 @@ module.exports = (function() { */ var support = {}; - (function() { - + (function () { /** * Detect if running in a browser environment. * * @memberOf Benchmark.support * @type boolean */ - support.browser = doc && isHostType(context, 'navigator') && !isHostType(context, 'phantom'); + support.browser = + doc && + isHostType(context, 'navigator') && + !isHostType(context, 'phantom'); /** * Detect if the Timers API exists. @@ -188,7 +264,9 @@ module.exports = (function() { * @memberOf Benchmark.support * @type boolean */ - support.timeout = isHostType(context, 'setTimeout') && isHostType(context, 'clearTimeout'); + support.timeout = + isHostType(context, 'setTimeout') && + isHostType(context, 'clearTimeout'); /** * Detect if function decompilation is support. @@ -202,15 +280,22 @@ module.exports = (function() { // See http://webk.it/11609 for more details. // Firefox 3.6 and Opera 9.25 strip grouping parentheses from `Function#toString` results. // See http://bugzil.la/559438 for more details. - support.decompilation = Function( - ('return (' + (function(x) { return { 'x': '' + (1 + x) + '', 'y': 0 }; }) + ')') - // Avoid issues with code added by Istanbul. - .replace(/__cov__[^;]+;/g, '') - )()(0).x === '1'; - } catch(e) { + support.decompilation = + Function( + ( + 'return (' + + function (x) { + return { x: '' + (1 + x) + '', y: 0 }; + } + + ')' + ) + // Avoid issues with code added by Istanbul. + .replace(/__cov__[^;]+;/g, ''), + )()(0).x === '1'; + } catch (e) { support.decompilation = false; } - }()); + })(); /** * Timer object used by `clock()` and `Deferred#resolve`. @@ -219,7 +304,6 @@ module.exports = (function() { * @type Object */ var timer = { - /** * The timer namespace object or constructor. * @@ -227,7 +311,7 @@ module.exports = (function() { * @memberOf timer * @type {Function|Object} */ - 'ns': Date, + ns: Date, /** * Starts the deferred timer. @@ -236,7 +320,7 @@ module.exports = (function() { * @memberOf timer * @param {Object} deferred The deferred instance. */ - 'start': null, // Lazy defined in `clock()`. + start: null, // Lazy defined in `clock()`. /** * Stops the deferred timer. @@ -245,7 +329,7 @@ module.exports = (function() { * @memberOf timer * @param {Object} deferred The deferred instance. */ - 'stop': null // Lazy defined in `clock()`. + stop: null, // Lazy defined in `clock()`. }; /*------------------------------------------------------------------------*/ @@ -342,19 +426,16 @@ module.exports = (function() { if (_.isPlainObject(name)) { // 1 argument (options). options = name; - } - else if (_.isFunction(name)) { + } else if (_.isFunction(name)) { // 2 arguments (fn, options). options = fn; fn = name; - } - else if (_.isPlainObject(fn)) { + } else if (_.isPlainObject(fn)) { // 2 arguments (name, options). options = fn; fn = null; bench.name = name; - } - else { + } else { // 3 arguments (name, fn [, options]). bench.name = name; } @@ -395,8 +476,12 @@ module.exports = (function() { if (type instanceof Event) { return type; } - return (event instanceof Event) - ? _.assign(event, { 'timeStamp': _.now() }, typeof type == 'string' ? { 'type': type } : type) + return event instanceof Event + ? _.assign( + event, + { timeStamp: _.now() }, + typeof type == 'string' ? { type: type } : type, + ) : new Event(type); } @@ -470,9 +555,9 @@ module.exports = (function() { * @param {*} value The value to clone. * @returns {*} The cloned value. */ - var cloneDeep = _.partial(_.cloneDeepWith, _, function(value) { + var cloneDeep = _.partial(_.cloneDeepWith, _, function (value) { // Only clone primitives, arrays, and plain objects. - return (_.isObject(value) && !_.isArray(value) && !_.isPlainObject(value)) + return _.isObject(value) && !_.isArray(value) && !_.isPlainObject(value) ? value : undefined; }); @@ -487,19 +572,31 @@ module.exports = (function() { */ function createFunction() { // Lazy define. - createFunction = function(args, body) { + createFunction = function (args, body) { var result, - anchor = freeDefine ? freeDefine.amd : Benchmark, - prop = uid + 'createFunction'; - - runScript((freeDefine ? 'define.amd.' : 'Benchmark.') + prop + '=function(' + args + '){' + body + '}'); + anchor = freeDefine ? freeDefine.amd : Benchmark, + prop = uid + 'createFunction'; + + runScript( + (freeDefine ? 'define.amd.' : 'Benchmark.') + + prop + + '=function(' + + args + + '){' + + body + + '}', + ); result = anchor[prop]; delete anchor[prop]; return result; }; // Fix JaegerMonkey bug. // For more information see http://bugzil.la/639720. - createFunction = support.browser && (createFunction('', 'return"' + uid + '"') || _.noop)() == uid ? createFunction : Function; + createFunction = + support.browser && + (createFunction('', 'return"' + uid + '"') || _.noop)() == uid + ? createFunction + : Function; return createFunction.apply(null, arguments); } @@ -533,8 +630,11 @@ module.exports = (function() { * @returns {string} The argument name. */ function getFirstArgument(fn) { - return (!_.has(fn, 'toString') && - (/^[\s(]*function[^(]*\(([^\s,)]+)/.exec(fn) || 0)[1]) || ''; + return ( + (!_.has(fn, 'toString') && + (/^[\s(]*function[^(]*\(([^\s,)]+)/.exec(fn) || 0)[1]) || + '' + ); } /** @@ -545,9 +645,11 @@ module.exports = (function() { * @returns {number} The mean. */ function getMean(sample) { - return (_.reduce(sample, function(sum, x) { - return sum + x; - }) / sample.length) || 0; + return ( + _.reduce(sample, function (sum, x) { + return sum + x; + }) / sample.length || 0 + ); } /** @@ -569,7 +671,9 @@ module.exports = (function() { result = (result || '').replace(/^\s+|\s+$/g, ''); // Detect strings containing only the "use strict" directive. - return /^(?:\/\*+[\w\W]*?\*\/|\/\/.*?[\n\r\u2028\u2029]|\s)*(["'])use strict\1;?$/.test(result) + return /^(?:\/\*+[\w\W]*?\*\/|\/\/.*?[\n\r\u2028\u2029]|\s)*(["'])use strict\1;?$/.test( + result, + ) ? '' : result; } @@ -601,7 +705,9 @@ module.exports = (function() { return false; } var type = typeof object[property]; - return !rePrimitive.test(type) && (type != 'object' || !!object[property]); + return ( + !rePrimitive.test(type) && (type != 'object' || !!object[property]) + ); } /** @@ -612,7 +718,10 @@ module.exports = (function() { * @returns {boolean} Returns `true` if the value can be coerced, else `false`. */ function isStringable(value) { - return _.isString(value) || (_.has(value, 'toString') && _.isFunction(value.toString)); + return ( + _.isString(value) || + (_.has(value, 'toString') && _.isFunction(value.toString)) + ); } /** @@ -623,11 +732,15 @@ module.exports = (function() { */ function runScript(code) { var anchor = freeDefine ? define.amd : Benchmark, - script = doc.createElement('script'), - sibling = doc.getElementsByTagName('script')[0], - parent = sibling.parentNode, - prop = uid + 'runScript', - prefix = '(' + (freeDefine ? 'define.amd.' : 'Benchmark.') + prop + '||function(){})();'; + script = doc.createElement('script'), + sibling = doc.getElementsByTagName('script')[0], + parent = sibling.parentNode, + prop = uid + 'runScript', + prefix = + '(' + + (freeDefine ? 'define.amd.' : 'Benchmark.') + + prop + + '||function(){})();'; // Firefox 2.0.0.2 cannot use script injection as intended because it executes // asynchronously, but that's OK because script injection is only used to avoid @@ -636,8 +749,10 @@ module.exports = (function() { // Remove the inserted script *before* running the code to avoid differences // in the expected script element count/order of the document. script.appendChild(doc.createTextNode(prefix + code)); - anchor[prop] = function() { destroyElement(script); }; - } catch(e) { + anchor[prop] = function () { + destroyElement(script); + }; + } catch (e) { parent = parent.cloneNode(false); sibling = null; script.text = code; @@ -654,13 +769,17 @@ module.exports = (function() { * @param {Object} [options={}] Options object. */ function setOptions(object, options) { - options = object.options = _.assign({}, cloneDeep(object.constructor.options), cloneDeep(options)); + options = object.options = _.assign( + {}, + cloneDeep(object.constructor.options), + cloneDeep(options), + ); - _.forOwn(options, function(value, key) { + _.forOwn(options, function (value, key) { if (value != null) { // Add event listeners. if (/^on[A-Z]/.test(key)) { - _.each(key.split(' '), function(key) { + _.each(key.split(' '), function (key) { object.on(key.slice(2).toLowerCase(), value); }); } else if (!_.has(object, key)) { @@ -679,22 +798,22 @@ module.exports = (function() { */ function resolve() { var deferred = this, - clone = deferred.benchmark, - bench = clone._original; + clone = deferred.benchmark, + bench = clone._original; if (bench.aborted) { // cycle() -> clone cycle/complete event -> compute()'s invoked bench.run() cycle/complete. deferred.teardown(); clone.running = false; cycle(deferred); - } - else if (++deferred.cycles < clone.count) { + } else if (++deferred.cycles < clone.count) { clone.compiled.call(deferred, context, timer); - } - else { + } else { timer.stop(deferred); deferred.teardown(); - delay(clone, function() { cycle(deferred); }); + delay(clone, function () { + cycle(deferred); + }); } } @@ -727,18 +846,21 @@ module.exports = (function() { function filter(array, callback) { if (callback === 'successful') { // Callback to exclude those that are errored, unrun, or have hz of Infinity. - callback = function(bench) { + callback = function (bench) { return bench.cycles && _.isFinite(bench.hz) && !bench.error; }; - } - else if (callback === 'fastest' || callback === 'slowest') { + } else if (callback === 'fastest' || callback === 'slowest') { // Get successful, sort by period + margin of error, and filter fastest/slowest. - var result = filter(array, 'successful').sort(function(a, b) { - a = a.stats; b = b.stats; - return (a.mean + a.moe > b.mean + b.moe ? 1 : -1) * (callback === 'fastest' ? 1 : -1); + var result = filter(array, 'successful').sort(function (a, b) { + a = a.stats; + b = b.stats; + return ( + (a.mean + a.moe > b.mean + b.moe ? 1 : -1) * + (callback === 'fastest' ? 1 : -1) + ); }); - return _.filter(result, function(bench) { + return _.filter(result, function (bench) { return result[0].compare(bench) == 0; }); } @@ -755,8 +877,10 @@ module.exports = (function() { */ function formatNumber(number) { number = String(number).split('.'); - return number[0].replace(/(?=(?:\d{3})+$)(?!\b)/g, ',') + - (number[1] ? '.' + number[1] : ''); + return ( + number[0].replace(/(?=(?:\d{3})+$)(?!\b)/g, ',') + + (number[1] ? '.' + number[1] : '') + ); } /** @@ -800,19 +924,19 @@ module.exports = (function() { */ function invoke(benches, name) { var args, - bench, - queued, - index = -1, - eventProps = { 'currentTarget': benches }, - options = { 'onStart': _.noop, 'onCycle': _.noop, 'onComplete': _.noop }, - result = _.toArray(benches); + bench, + queued, + index = -1, + eventProps = { currentTarget: benches }, + options = { onStart: _.noop, onCycle: _.noop, onComplete: _.noop }, + result = _.toArray(benches); /** * Invokes the method of the current object and if synchronous, fetches the next. */ function execute() { var listeners, - async = isAsync(bench); + async = isAsync(bench); if (async) { // Use `getNext` as the first listener. @@ -821,7 +945,9 @@ module.exports = (function() { listeners.splice(0, 0, listeners.pop()); } // Execute method. - result[index] = _.isFunction(bench && bench[name]) ? bench[name].apply(bench, args) : undefined; + result[index] = _.isFunction(bench && bench[name]) + ? bench[name].apply(bench, args) + : undefined; // If synchronous return `true` until finished. return !async && getNext(); } @@ -831,8 +957,8 @@ module.exports = (function() { */ function getNext(event) { var cycleEvent, - last = bench, - async = isAsync(last); + last = bench, + async = isAsync(last); if (async) { last.off('complete', getNext); @@ -849,12 +975,10 @@ module.exports = (function() { bench = queued ? benches[0] : result[index]; if (isAsync(bench)) { delay(bench, execute); - } - else if (async) { + } else if (async) { // Resume execution if previously asynchronous but now synchronous. while (execute()) {} - } - else { + } else { // Continue synchronous execution. return true; } @@ -879,8 +1003,13 @@ module.exports = (function() { function isAsync(object) { // Avoid using `instanceof` here because of IE memory leak issues with host objects. var async = args[0] && args[0].async; - return name == 'run' && (object instanceof Benchmark) && - ((async == null ? object.options.async : async) && support.timeout || object.defer); + return ( + name == 'run' && + object instanceof Benchmark && + (((async == null ? object.options.async : async) && + support.timeout) || + object.defer) + ); } /** @@ -906,7 +1035,9 @@ module.exports = (function() { // 2 arguments (array, options). options = _.assign(options, name); name = options.name; - args = _.isArray(args = 'args' in options ? options.args : []) ? args : [args]; + args = _.isArray((args = 'args' in options ? options.args : [])) + ? args + : [args]; queued = options.queued; } // Start iterating over the array. @@ -918,7 +1049,7 @@ module.exports = (function() { options.onStart.call(benches, Event(eventProps)); // End early if the suite was aborted in an "onStart" listener. - if (name == 'run' && (benches instanceof Suite) && benches.aborted) { + if (name == 'run' && benches instanceof Suite && benches.aborted) { // Emit "cycle" event. eventProps.type = 'cycle'; options.onCycle.call(benches, Event(eventProps)); @@ -950,11 +1081,11 @@ module.exports = (function() { */ function join(object, separator1, separator2) { var result = [], - length = (object = Object(object)).length, - arrayLike = length === length >>> 0; + length = (object = Object(object)).length, + arrayLike = length === length >>> 0; separator2 || (separator2 = ': '); - _.each(object, function(value, key) { + _.each(object, function (value, key) { result.push(arrayLike ? value : key + separator2 + value); }); return result.join(separator1 || ','); @@ -971,8 +1102,8 @@ module.exports = (function() { */ function abortSuite() { var event, - suite = this, - resetting = calledBy.resetSuite; + suite = this, + resetting = calledBy.resetSuite; if (suite.running) { event = Event('abort'); @@ -1031,10 +1162,10 @@ module.exports = (function() { */ function add(name, fn, options) { var suite = this, - bench = new Benchmark(name, fn, options), - event = Event({ 'type': 'add', 'target': bench }); + bench = new Benchmark(name, fn, options), + event = Event({ type: 'add', target: bench }); - if (suite.emit(event), !event.cancelled) { + if ((suite.emit(event), !event.cancelled)) { suite.push(bench); } return suite; @@ -1050,14 +1181,15 @@ module.exports = (function() { */ function cloneSuite(options) { var suite = this, - result = new suite.constructor(_.assign({}, suite.options, options)); + result = new suite.constructor(_.assign({}, suite.options, options)); // Copy own properties. - _.forOwn(suite, function(value, key) { + _.forOwn(suite, function (value, key) { if (!_.has(result, key)) { - result[key] = value && _.isFunction(value.clone) - ? value.clone() - : cloneDeep(value); + result[key] = + value && _.isFunction(value.clone) + ? value.clone() + : cloneDeep(value); } }); return result; @@ -1073,7 +1205,7 @@ module.exports = (function() { */ function filterSuite(callback) { var suite = this, - result = new suite.constructor(suite.options); + result = new suite.constructor(suite.options); result.push.apply(result, filter(suite, callback)); return result; @@ -1088,8 +1220,8 @@ module.exports = (function() { */ function resetSuite() { var event, - suite = this, - aborting = calledBy.abortSuite; + suite = this, + aborting = calledBy.abortSuite; if (suite.running && !aborting) { // No worries, `resetSuite()` is called within `abortSuite()`. @@ -1098,8 +1230,10 @@ module.exports = (function() { delete calledBy.resetSuite; } // Reset if the state has changed. - else if ((suite.aborted || suite.running) && - (suite.emit(event = Event('reset')), !event.cancelled)) { + else if ( + (suite.aborted || suite.running) && + (suite.emit((event = Event('reset'))), !event.cancelled) + ) { suite.aborted = suite.running = false; if (!aborting) { invoke(suite, 'reset'); @@ -1131,24 +1265,24 @@ module.exports = (function() { options || (options = {}); invoke(suite, { - 'name': 'run', - 'args': options, - 'queued': options.queued, - 'onStart': function(event) { + name: 'run', + args: options, + queued: options.queued, + onStart: function (event) { suite.emit(event); }, - 'onCycle': function(event) { + onCycle: function (event) { var bench = event.target; if (bench.error) { - suite.emit({ 'type': 'error', 'target': bench }); + suite.emit({ type: 'error', target: bench }); } suite.emit(event); event.aborted = suite.aborted; }, - 'onComplete': function(event) { + onComplete: function (event) { suite.running = false; suite.emit(event); - } + }, }); return suite; } @@ -1165,17 +1299,20 @@ module.exports = (function() { */ function emit(type) { var listeners, - object = this, - event = Event(type), - events = object.events, - args = (arguments[0] = event, arguments); + object = this, + event = Event(type), + events = object.events, + args = ((arguments[0] = event), arguments); event.currentTarget || (event.currentTarget = object); event.target || (event.target = object); delete event.result; - if (events && (listeners = _.has(events, event.type) && events[event.type])) { - _.each(listeners.slice(), function(listener) { + if ( + events && + (listeners = _.has(events, event.type) && events[event.type]) + ) { + _.each(listeners.slice(), function (listener) { if ((event.result = listener.apply(object, args)) === false) { event.cancelled = true; } @@ -1195,7 +1332,7 @@ module.exports = (function() { */ function listeners(type) { var object = this, - events = object.events || (object.events = {}); + events = object.events || (object.events = {}); return _.has(events, type) ? events[type] : (events[type] = []); } @@ -1228,12 +1365,12 @@ module.exports = (function() { */ function off(type, listener) { var object = this, - events = object.events; + events = object.events; if (!events) { return object; } - _.each(type ? type.split(' ') : events, function(listeners, type) { + _.each(type ? type.split(' ') : events, function (listeners, type) { var index; if (typeof listeners == 'string') { type = listeners; @@ -1270,13 +1407,12 @@ module.exports = (function() { */ function on(type, listener) { var object = this, - events = object.events || (object.events = {}); + events = object.events || (object.events = {}); - _.each(type.split(' '), function(type) { - (_.has(events, type) - ? events[type] - : (events[type] = []) - ).push(listener); + _.each(type.split(' '), function (type) { + (_.has(events, type) ? events[type] : (events[type] = [])).push( + listener, + ); }); return object; } @@ -1291,8 +1427,8 @@ module.exports = (function() { */ function abort() { var event, - bench = this, - resetting = calledBy.reset; + bench = this, + resetting = calledBy.reset; if (bench.running) { event = Event('abort'); @@ -1330,13 +1466,17 @@ module.exports = (function() { */ function clone(options) { var bench = this, - result = new bench.constructor(_.assign({}, bench, options)); + result = new bench.constructor(_.assign({}, bench, options)); // Correct the `options` object. - result.options = _.assign({}, cloneDeep(bench.options), cloneDeep(options)); + result.options = _.assign( + {}, + cloneDeep(bench.options), + cloneDeep(options), + ); // Copy own custom properties. - _.forOwn(bench, function(value, key) { + _.forOwn(bench, function (value, key) { if (!_.has(result, key)) { result[key] = cloneDeep(value); } @@ -1360,31 +1500,42 @@ module.exports = (function() { return 0; } var critical, - zStat, - sample1 = bench.stats.sample, - sample2 = other.stats.sample, - size1 = sample1.length, - size2 = sample2.length, - maxSize = max(size1, size2), - minSize = min(size1, size2), - u1 = getU(sample1, sample2), - u2 = getU(sample2, sample1), - u = min(u1, u2); + zStat, + sample1 = bench.stats.sample, + sample2 = other.stats.sample, + size1 = sample1.length, + size2 = sample2.length, + maxSize = max(size1, size2), + minSize = min(size1, size2), + u1 = getU(sample1, sample2), + u2 = getU(sample2, sample1), + u = min(u1, u2); function getScore(xA, sampleB) { - return _.reduce(sampleB, function(total, xB) { - return total + (xB > xA ? 0 : xB < xA ? 1 : 0.5); - }, 0); + return _.reduce( + sampleB, + function (total, xB) { + return total + (xB > xA ? 0 : xB < xA ? 1 : 0.5); + }, + 0, + ); } function getU(sampleA, sampleB) { - return _.reduce(sampleA, function(total, xA) { - return total + getScore(xA, sampleB); - }, 0); + return _.reduce( + sampleA, + function (total, xA) { + return total + getScore(xA, sampleB); + }, + 0, + ); } function getZ(u) { - return (u - ((size1 * size2) / 2)) / sqrt((size1 * size2 * (size1 + size2 + 1)) / 12); + return ( + (u - (size1 * size2) / 2) / + sqrt((size1 * size2 * (size1 + size2 + 1)) / 12) + ); } // Reject the null hypothesis the two samples come from the // same population (i.e. have the same median) if... @@ -1415,22 +1566,26 @@ module.exports = (function() { return bench; } var event, - index = 0, - changes = [], - queue = []; + index = 0, + changes = [], + queue = []; // A non-recursive solution to check if properties have changed. // For more information see http://www.jslab.dk/articles/non.recursive.preorder.traversal.part4. var data = { - 'destination': bench, - 'source': _.assign({}, cloneDeep(bench.constructor.prototype), cloneDeep(bench.options)) + destination: bench, + source: _.assign( + {}, + cloneDeep(bench.constructor.prototype), + cloneDeep(bench.options), + ), }; do { - _.forOwn(data.source, function(value, key) { + _.forOwn(data.source, function (value, key) { var changed, - destination = data.destination, - currValue = destination[key]; + destination = data.destination, + currValue = destination[key]; // Skip pseudo private properties like `_timerId` which could be a // Java object in environments like RingoJS. @@ -1455,21 +1610,30 @@ module.exports = (function() { } // Register a changed object. if (changed) { - changes.push({ 'destination': destination, 'key': key, 'value': currValue }); + changes.push({ + destination: destination, + key: key, + value: currValue, + }); } - queue.push({ 'destination': currValue, 'source': value }); + queue.push({ destination: currValue, source: value }); } // Register a changed primitive. - else if (value !== currValue && !(value == null || _.isFunction(value))) { - changes.push({ 'destination': destination, 'key': key, 'value': value }); + else if ( + value !== currValue && + !(value == null || _.isFunction(value)) + ) { + changes.push({ destination: destination, key: key, value: value }); } }); - } - while ((data = queue[index++])); + } while ((data = queue[index++])); // If changed emit the `reset` event and if it isn't cancelled reset the benchmark. - if (changes.length && (bench.emit(event = Event('reset')), !event.cancelled)) { - _.each(changes, function(data) { + if ( + changes.length && + (bench.emit((event = Event('reset'))), !event.cancelled) + ) { + _.each(changes, function (data) { data.destination[data.key] = data.value; }); } @@ -1485,13 +1649,13 @@ module.exports = (function() { */ function toStringBench() { var bench = this, - error = bench.error, - hz = bench.hz, - id = bench.id, - stats = bench.stats, - size = stats.sample.length, - pm = '\xb1', - result = bench.name || (_.isNaN(id) ? id : ''); + error = bench.error, + hz = bench.hz, + id = bench.id, + stats = bench.stats, + size = stats.sample.length, + pm = '\xb1', + result = bench.name || (_.isNaN(id) ? id : ''); if (error) { var errorStr; @@ -1501,13 +1665,23 @@ module.exports = (function() { errorStr = join(error); } else { // Error#name and Error#message properties are non-enumerable. - errorStr = join(_.assign({ 'name': error.name, 'message': error.message }, error)); + errorStr = join( + _.assign({ name: error.name, message: error.message }, error), + ); } result += ': ' + errorStr; - } - else { - result += ' x ' + formatNumber(hz.toFixed(hz < 100 ? 2 : 0)) + ' ops/sec ' + pm + - stats.rme.toFixed(2) + '% (' + size + ' run' + (size == 1 ? '' : 's') + ' sampled)'; + } else { + result += + ' x ' + + formatNumber(hz.toFixed(hz < 100 ? 2 : 0)) + + ' ops/sec ' + + pm + + stats.rme.toFixed(2) + + '% (' + + size + + ' run' + + (size == 1 ? '' : 's') + + ' sampled)'; } return result; } @@ -1523,11 +1697,11 @@ module.exports = (function() { */ function clock() { var options = Benchmark.options, - templateData = {}, - timers = [{ 'ns': timer.ns, 'res': max(0.0015, getRes('ms')), 'unit': 'ms' }]; + templateData = {}, + timers = [{ ns: timer.ns, res: max(0.0015, getRes('ms')), unit: 'ms' }]; // Lazy define for hi-res timers. - clock = function(clone) { + clock = function (clone) { var deferred; if (clone instanceof Deferred) { @@ -1535,15 +1709,21 @@ module.exports = (function() { clone = deferred.benchmark; } var bench = clone._original, - stringable = isStringable(bench.fn), - count = bench.count = clone.count, - decompilable = stringable || (support.decompilation && (clone.setup !== _.noop || clone.teardown !== _.noop)), - id = bench.id, - name = bench.name || (typeof id == 'number' ? '' : id), - result = 0; + stringable = isStringable(bench.fn), + count = (bench.count = clone.count), + decompilable = + stringable || + (support.decompilation && + (clone.setup !== _.noop || clone.teardown !== _.noop)), + id = bench.id, + name = + bench.name || (typeof id == 'number' ? '' : id), + result = 0; // Init `minTime` if needed. - clone.minTime = bench.minTime || (bench.minTime = bench.options.minTime = options.minTime); + clone.minTime = + bench.minTime || + (bench.minTime = bench.options.minTime = options.minTime); // Compile in setup/teardown functions and the test loop. // Create a new compiled test, instead of using the cached `bench.compiled`, @@ -1562,38 +1742,46 @@ module.exports = (function() { 't#.start(d#);' + // and then execute `deferred.fn` and return a dummy object. '}d#.fn();return{uid:"${uid}"}' - : 'var r#,s#,m#=this,f#=m#.fn,i#=m#.count,n#=t#.ns;${setup}\n${begin};' + 'while(i#--){${fn}\n}${end};${teardown}\nreturn{elapsed:r#,uid:"${uid}"}'; - var compiled = bench.compiled = clone.compiled = createCompiled(bench, decompilable, deferred, funcBody), - isEmpty = !(templateData.fn || stringable); + var compiled = + (bench.compiled = + clone.compiled = + createCompiled(bench, decompilable, deferred, funcBody)), + isEmpty = !(templateData.fn || stringable); try { if (isEmpty) { // Firefox may remove dead code from `Function#toString` results. // For more information see http://bugzil.la/536085. - throw new Error('The test "' + name + '" is empty. This may be the result of dead code removal.'); - } - else if (!deferred) { + throw new Error( + 'The test "' + + name + + '" is empty. This may be the result of dead code removal.', + ); + } else if (!deferred) { // Pretest to determine if compiled code exits early, usually by a // rogue `return` statement, by checking for a return object with the uid. bench.count = 1; - compiled = decompilable && (compiled.call(bench, context, timer) || {}).uid == templateData.uid && compiled; + compiled = + decompilable && + (compiled.call(bench, context, timer) || {}).uid == + templateData.uid && + compiled; bench.count = count; } - } catch(e) { + } catch (e) { compiled = null; clone.error = e || new Error(String(e)); bench.count = count; } // Fallback when a test exits early or errors during pretest. if (!compiled && !deferred && !isEmpty) { - funcBody = ( - stringable || (decompilable && !clone.error) + funcBody = + (stringable || (decompilable && !clone.error) ? 'function f#(){${fn}\n}var r#,s#,m#=this,i#=m#.count' - : 'var r#,s#,m#=this,f#=m#.fn,i#=m#.count' - ) + + : 'var r#,s#,m#=this,f#=m#.fn,i#=m#.count') + ',n#=t#.ns;${setup}\n${begin};m#.f#=f#;while(i#--){m#.f#()}${end};' + 'delete m#.f#;${teardown}\nreturn{elapsed:r#}'; @@ -1605,8 +1793,7 @@ module.exports = (function() { compiled.call(bench, context, timer); bench.count = count; delete clone.error; - } - catch(e) { + } catch (e) { bench.count = count; if (!clone.error) { clone.error = e || new Error(String(e)); @@ -1615,7 +1802,10 @@ module.exports = (function() { } // If no errors run the full test loop. if (!clone.error) { - compiled = bench.compiled = clone.compiled = createCompiled(bench, decompilable, deferred, funcBody); + compiled = + bench.compiled = + clone.compiled = + createCompiled(bench, decompilable, deferred, funcBody); result = compiled.call(deferred || bench, context, timer).elapsed; } return result; @@ -1628,65 +1818,68 @@ module.exports = (function() { */ function createCompiled(bench, decompilable, deferred, body) { var fn = bench.fn, - fnArg = deferred ? getFirstArgument(fn) || 'deferred' : ''; + fnArg = deferred ? getFirstArgument(fn) || 'deferred' : ''; templateData.uid = uid + uidCounter++; _.assign(templateData, { - 'setup': decompilable ? getSource(bench.setup) : interpolate('m#.setup()'), - 'fn': decompilable ? getSource(fn) : interpolate('m#.fn(' + fnArg + ')'), - 'fnArg': fnArg, - 'teardown': decompilable ? getSource(bench.teardown) : interpolate('m#.teardown()') + setup: decompilable + ? getSource(bench.setup) + : interpolate('m#.setup()'), + fn: decompilable + ? getSource(fn) + : interpolate('m#.fn(' + fnArg + ')'), + fnArg: fnArg, + teardown: decompilable + ? getSource(bench.teardown) + : interpolate('m#.teardown()'), }); // Use API of chosen timer. if (timer.unit == 'ns') { _.assign(templateData, { - 'begin': interpolate('s#=n#()'), - 'end': interpolate('r#=n#(s#);r#=r#[0]+(r#[1]/1e9)') + begin: interpolate('s#=n#()'), + end: interpolate('r#=n#(s#);r#=r#[0]+(r#[1]/1e9)'), }); - } - else if (timer.unit == 'us') { + } else if (timer.unit == 'us') { if (timer.ns.stop) { _.assign(templateData, { - 'begin': interpolate('s#=n#.start()'), - 'end': interpolate('r#=n#.microseconds()/1e6') + begin: interpolate('s#=n#.start()'), + end: interpolate('r#=n#.microseconds()/1e6'), }); } else { _.assign(templateData, { - 'begin': interpolate('s#=n#()'), - 'end': interpolate('r#=(n#()-s#)/1e6') + begin: interpolate('s#=n#()'), + end: interpolate('r#=(n#()-s#)/1e6'), }); } - } - else if (timer.ns.now) { + } else if (timer.ns.now) { _.assign(templateData, { - 'begin': interpolate('s#=n#.now()'), - 'end': interpolate('r#=(n#.now()-s#)/1e3') + begin: interpolate('s#=n#.now()'), + end: interpolate('r#=(n#.now()-s#)/1e3'), }); - } - else { + } else { _.assign(templateData, { - 'begin': interpolate('s#=new n#().getTime()'), - 'end': interpolate('r#=(new n#().getTime()-s#)/1e3') + begin: interpolate('s#=new n#().getTime()'), + end: interpolate('r#=(new n#().getTime()-s#)/1e3'), }); } // Define `timer` methods. timer.start = createFunction( interpolate('o#'), - interpolate('var n#=this.ns,${begin};o#.elapsed=0;o#.timeStamp=s#') + interpolate('var n#=this.ns,${begin};o#.elapsed=0;o#.timeStamp=s#'), ); timer.stop = createFunction( interpolate('o#'), - interpolate('var n#=this.ns,s#=o#.timeStamp,${end};o#.elapsed=r#') + interpolate('var n#=this.ns,s#=o#.timeStamp,${end};o#.elapsed=r#'), ); // Create compiled test. return createFunction( interpolate('window,t#'), 'var global = window, clearTimeout = global.clearTimeout, setTimeout = global.setTimeout;\n' + - interpolate(body) + interpolate(body), ); } @@ -1695,11 +1888,11 @@ module.exports = (function() { */ function getRes(unit) { var measured, - begin, - count = 30, - divisor = 1e3, - ns = timer.ns, - sample = []; + begin, + count = 30, + divisor = 1e3, + ns = timer.ns, + sample = []; // Get average smallest measurable time. while (count--) { @@ -1712,18 +1905,17 @@ module.exports = (function() { begin = ns(); while (!(measured = ns() - begin)) {} } - } - else if (unit == 'ns') { + } else if (unit == 'ns') { divisor = 1e9; - begin = (begin = ns())[0] + (begin[1] / divisor); - while (!(measured = ((measured = ns())[0] + (measured[1] / divisor)) - begin)) {} + begin = (begin = ns())[0] + begin[1] / divisor; + while ( + !(measured = (measured = ns())[0] + measured[1] / divisor - begin) + ) {} divisor = 1; - } - else if (ns.now) { + } else if (ns.now) { begin = ns.now(); while (!(measured = ns.now() - begin)) {} - } - else { + } else { begin = new ns().getTime(); while (!(measured = new ns().getTime() - begin)) {} } @@ -1744,7 +1936,9 @@ module.exports = (function() { */ function interpolate(string) { // Replaces all occurrences of `#` with a unique number and template tokens with content. - return _.template(string.replace(/\#/g, /\d+/.exec(templateData.uid)))(templateData); + return _.template(string.replace(/\#/g, /\d+/.exec(templateData.uid)))( + templateData, + ); } /*----------------------------------------------------------------------*/ @@ -1753,14 +1947,17 @@ module.exports = (function() { // enable benchmarking via the --enable-benchmarking command // line switch in at least Chrome 7 to use chrome.Interval try { - if ((timer.ns = new (context.chrome || context.chromium).Interval)) { - timers.push({ 'ns': timer.ns, 'res': getRes('us'), 'unit': 'us' }); + if ((timer.ns = new (context.chrome || context.chromium).Interval())) { + timers.push({ ns: timer.ns, res: getRes('us'), unit: 'us' }); } - } catch(e) {} + } catch (e) {} // Detect Node.js's nanosecond resolution timer available in Node.js >= 0.8. - if (processObject && typeof (timer.ns = processObject.hrtime) == 'function') { - timers.push({ 'ns': timer.ns, 'res': getRes('ns'), 'unit': 'ns' }); + if ( + processObject && + typeof (timer.ns = processObject.hrtime) == 'function' + ) { + timers.push({ ns: timer.ns, res: getRes('ns'), unit: 'ns' }); } // Pick timer with highest resolution. timer = _.minBy(timers, 'res'); @@ -1788,25 +1985,27 @@ module.exports = (function() { options || (options = {}); var async = options.async, - elapsed = 0, - initCount = bench.initCount, - minSamples = bench.minSamples, - queue = [], - sample = bench.stats.sample; + elapsed = 0, + initCount = bench.initCount, + minSamples = bench.minSamples, + queue = [], + sample = bench.stats.sample; /** * Adds a clone to the queue. */ function enqueue() { - queue.push(bench.clone({ - '_original': bench, - 'events': { - 'abort': [update], - 'cycle': [update], - 'error': [update], - 'start': [update] - } - })); + queue.push( + bench.clone({ + _original: bench, + events: { + abort: [update], + cycle: [update], + error: [update], + start: [update], + }, + }), + ); } /** @@ -1814,14 +2013,13 @@ module.exports = (function() { */ function update(event) { var clone = this, - type = event.type; + type = event.type; if (bench.running) { if (type == 'start') { // Note: `clone.minTime` prop is inited in `clock()`. clone.count = bench.initCount; - } - else { + } else { if (type == 'error') { bench.error = clone.error; } @@ -1845,20 +2043,24 @@ module.exports = (function() { */ function evaluate(event) { var critical, - df, - mean, - moe, - rme, - sd, - sem, - variance, - clone = event.target, - done = bench.aborted, - now = _.now(), - size = sample.push(clone.times.period), - maxedOut = size >= minSamples && (elapsed += now - clone.times.timeStamp) / 1e3 > bench.maxTime, - times = bench.times, - varOf = function(sum, x) { return sum + pow(x - mean, 2); }; + df, + mean, + moe, + rme, + sd, + sem, + variance, + clone = event.target, + done = bench.aborted, + now = _.now(), + size = sample.push(clone.times.period), + maxedOut = + size >= minSamples && + (elapsed += now - clone.times.timeStamp) / 1e3 > bench.maxTime, + times = bench.times, + varOf = function (sum, x) { + return sum + pow(x - mean, 2); + }; // Exit early for aborted or unclockable tests. if (done || clone.hz == Infinity) { @@ -1884,12 +2086,12 @@ module.exports = (function() { rme = (moe / mean) * 100 || 0; _.assign(bench.stats, { - 'deviation': sd, - 'mean': mean, - 'moe': moe, - 'rme': rme, - 'sem': sem, - 'variance': variance + deviation: sd, + mean: mean, + moe: moe, + rme: rme, + sem: sem, + variance: variance, }); // Abort the cycle loop when the minimum sample size has been collected @@ -1921,11 +2123,13 @@ module.exports = (function() { // Init queue and begin. enqueue(); invoke(queue, { - 'name': 'run', - 'args': { 'async': async }, - 'queued': true, - 'onCycle': evaluate, - 'onComplete': function() { bench.emit('complete'); } + name: 'run', + args: { async: async }, + queued: true, + onCycle: evaluate, + onComplete: function () { + bench.emit('complete'); + }, }); } @@ -1947,15 +2151,15 @@ module.exports = (function() { clone = clone.benchmark; } var clocked, - cycles, - divisor, - event, - minTime, - period, - async = options.async, - bench = clone._original, - count = clone.count, - times = clone.times; + cycles, + divisor, + event, + minTime, + period, + async = options.async, + bench = clone._original, + count = clone.count, + times = clone.times; // Continue, if not aborted between cycles. if (clone.running) { @@ -2015,12 +2219,13 @@ module.exports = (function() { if (deferred) { clone.compiled.call(deferred, context, timer); } else if (async) { - delay(clone, function() { cycle(clone, options); }); + delay(clone, function () { + cycle(clone, options); + }); } else { cycle(clone); } - } - else { + } else { // Fix TraceMonkey bug associated with clock fallbacks. // For more information see http://bugzil.la/509069. if (support.browser) { @@ -2049,7 +2254,7 @@ module.exports = (function() { */ function run(options) { var bench = this, - event = Event('start'); + event = Event('start'); // Set `running` to `false` so `reset()` won't call `abort()`. bench.running = false; @@ -2061,7 +2266,12 @@ module.exports = (function() { bench.emit(event); if (!event.cancelled) { - options = { 'async': ((options = options && options.async) == null ? bench.async : options) && support.timeout }; + options = { + async: + ((options = options && options.async) == null + ? bench.async + : options) && support.timeout, + }; // For clones created within `compute()`. if (bench._original) { @@ -2088,7 +2298,6 @@ module.exports = (function() { // making it non-writable in the process, unless it is the first property // assigned by for-in loop of `_.assign()`. _.assign(Benchmark, { - /** * The default options copied by benchmark instances. * @@ -2096,8 +2305,7 @@ module.exports = (function() { * @memberOf Benchmark * @type Object */ - 'options': { - + options: { /** * A flag to indicate that benchmark cycles will execute asynchronously * by default. @@ -2105,7 +2313,7 @@ module.exports = (function() { * @memberOf Benchmark.options * @type boolean */ - 'async': false, + async: false, /** * A flag to indicate that the benchmark clock is deferred. @@ -2113,14 +2321,14 @@ module.exports = (function() { * @memberOf Benchmark.options * @type boolean */ - 'defer': false, + defer: false, /** * The delay between test cycles (secs). * @memberOf Benchmark.options * @type number */ - 'delay': 0.005, + delay: 0.005, /** * Displayed by `Benchmark#toString` when a `name` is not available @@ -2129,7 +2337,7 @@ module.exports = (function() { * @memberOf Benchmark.options * @type string */ - 'id': undefined, + id: undefined, /** * The default number of times to execute a test on a benchmark's first cycle. @@ -2137,7 +2345,7 @@ module.exports = (function() { * @memberOf Benchmark.options * @type number */ - 'initCount': 1, + initCount: 1, /** * The maximum time a benchmark is allowed to run before finishing (secs). @@ -2147,7 +2355,7 @@ module.exports = (function() { * @memberOf Benchmark.options * @type number */ - 'maxTime': 5, + maxTime: 5, /** * The minimum sample size required to perform statistical analysis. @@ -2155,7 +2363,7 @@ module.exports = (function() { * @memberOf Benchmark.options * @type number */ - 'minSamples': 5, + minSamples: 5, /** * The time needed to reduce the percent uncertainty of measurement to 1% (secs). @@ -2163,7 +2371,7 @@ module.exports = (function() { * @memberOf Benchmark.options * @type number */ - 'minTime': 0, + minTime: 0, /** * The name of the benchmark. @@ -2171,7 +2379,7 @@ module.exports = (function() { * @memberOf Benchmark.options * @type string */ - 'name': undefined, + name: undefined, /** * An event listener called when the benchmark is aborted. @@ -2179,7 +2387,7 @@ module.exports = (function() { * @memberOf Benchmark.options * @type Function */ - 'onAbort': undefined, + onAbort: undefined, /** * An event listener called when the benchmark completes running. @@ -2187,7 +2395,7 @@ module.exports = (function() { * @memberOf Benchmark.options * @type Function */ - 'onComplete': undefined, + onComplete: undefined, /** * An event listener called after each run cycle. @@ -2195,7 +2403,7 @@ module.exports = (function() { * @memberOf Benchmark.options * @type Function */ - 'onCycle': undefined, + onCycle: undefined, /** * An event listener called when a test errors. @@ -2203,7 +2411,7 @@ module.exports = (function() { * @memberOf Benchmark.options * @type Function */ - 'onError': undefined, + onError: undefined, /** * An event listener called when the benchmark is reset. @@ -2211,7 +2419,7 @@ module.exports = (function() { * @memberOf Benchmark.options * @type Function */ - 'onReset': undefined, + onReset: undefined, /** * An event listener called when the benchmark starts running. @@ -2219,7 +2427,7 @@ module.exports = (function() { * @memberOf Benchmark.options * @type Function */ - 'onStart': undefined + onStart: undefined, }, /** @@ -2230,19 +2438,21 @@ module.exports = (function() { * @memberOf Benchmark * @type Object */ - 'platform': context.platform || require('platform') || ({ - 'description': context.navigator && context.navigator.userAgent || null, - 'layout': null, - 'product': null, - 'name': null, - 'manufacturer': null, - 'os': null, - 'prerelease': null, - 'version': null, - 'toString': function() { - return this.description || ''; - } - }), + platform: context.platform || + require('platform') || { + description: + (context.navigator && context.navigator.userAgent) || null, + layout: null, + product: null, + name: null, + manufacturer: null, + os: null, + prerelease: null, + version: null, + toString: function () { + return this.description || ''; + }, + }, /** * The semantic version number. @@ -2251,34 +2461,36 @@ module.exports = (function() { * @memberOf Benchmark * @type string */ - 'version': '2.1.2' + version: '2.1.2', }); _.assign(Benchmark, { - 'filter': filter, - 'formatNumber': formatNumber, - 'invoke': invoke, - 'join': join, - 'runInContext': runInContext, - 'support': support + filter: filter, + formatNumber: formatNumber, + invoke: invoke, + join: join, + runInContext: runInContext, + support: support, }); // Add lodash methods to Benchmark. - _.each(['each', 'forEach', 'forOwn', 'has', 'indexOf', 'map', 'reduce'], function(methodName) { - Benchmark[methodName] = _[methodName]; - }); + _.each( + ['each', 'forEach', 'forOwn', 'has', 'indexOf', 'map', 'reduce'], + function (methodName) { + Benchmark[methodName] = _[methodName]; + }, + ); /*------------------------------------------------------------------------*/ _.assign(Benchmark.prototype, { - /** * The number of times a test was executed. * * @memberOf Benchmark * @type number */ - 'count': 0, + count: 0, /** * The number of cycles performed while benchmarking. @@ -2286,7 +2498,7 @@ module.exports = (function() { * @memberOf Benchmark * @type number */ - 'cycles': 0, + cycles: 0, /** * The number of executions per second. @@ -2294,7 +2506,7 @@ module.exports = (function() { * @memberOf Benchmark * @type number */ - 'hz': 0, + hz: 0, /** * The compiled test function. @@ -2302,7 +2514,7 @@ module.exports = (function() { * @memberOf Benchmark * @type {Function|string} */ - 'compiled': undefined, + compiled: undefined, /** * The error object if the test failed. @@ -2310,7 +2522,7 @@ module.exports = (function() { * @memberOf Benchmark * @type Object */ - 'error': undefined, + error: undefined, /** * The test to benchmark. @@ -2318,7 +2530,7 @@ module.exports = (function() { * @memberOf Benchmark * @type {Function|string} */ - 'fn': undefined, + fn: undefined, /** * A flag to indicate if the benchmark is aborted. @@ -2326,7 +2538,7 @@ module.exports = (function() { * @memberOf Benchmark * @type boolean */ - 'aborted': false, + aborted: false, /** * A flag to indicate if the benchmark is running. @@ -2334,7 +2546,7 @@ module.exports = (function() { * @memberOf Benchmark * @type boolean */ - 'running': false, + running: false, /** * Compiled into the test and executed immediately **before** the test loop. @@ -2397,7 +2609,7 @@ module.exports = (function() { * }()) * }()) */ - 'setup': _.noop, + setup: _.noop, /** * Compiled into the test and executed immediately **after** the test loop. @@ -2405,7 +2617,7 @@ module.exports = (function() { * @memberOf Benchmark * @type {Function|string} */ - 'teardown': _.noop, + teardown: _.noop, /** * An object of stats including mean, margin or error, and standard deviation. @@ -2413,15 +2625,14 @@ module.exports = (function() { * @memberOf Benchmark * @type Object */ - 'stats': { - + stats: { /** * The margin of error. * * @memberOf Benchmark#stats * @type number */ - 'moe': 0, + moe: 0, /** * The relative margin of error (expressed as a percentage of the mean). @@ -2429,7 +2640,7 @@ module.exports = (function() { * @memberOf Benchmark#stats * @type number */ - 'rme': 0, + rme: 0, /** * The standard error of the mean. @@ -2437,7 +2648,7 @@ module.exports = (function() { * @memberOf Benchmark#stats * @type number */ - 'sem': 0, + sem: 0, /** * The sample standard deviation. @@ -2445,7 +2656,7 @@ module.exports = (function() { * @memberOf Benchmark#stats * @type number */ - 'deviation': 0, + deviation: 0, /** * The sample arithmetic mean (secs). @@ -2453,7 +2664,7 @@ module.exports = (function() { * @memberOf Benchmark#stats * @type number */ - 'mean': 0, + mean: 0, /** * The array of sampled periods. @@ -2461,7 +2672,7 @@ module.exports = (function() { * @memberOf Benchmark#stats * @type Array */ - 'sample': [], + sample: [], /** * The sample variance. @@ -2469,7 +2680,7 @@ module.exports = (function() { * @memberOf Benchmark#stats * @type number */ - 'variance': 0 + variance: 0, }, /** @@ -2478,15 +2689,14 @@ module.exports = (function() { * @memberOf Benchmark * @type Object */ - 'times': { - + times: { /** * The time taken to complete the last cycle (secs). * * @memberOf Benchmark#times * @type number */ - 'cycle': 0, + cycle: 0, /** * The time taken to complete the benchmark (secs). @@ -2494,7 +2704,7 @@ module.exports = (function() { * @memberOf Benchmark#times * @type number */ - 'elapsed': 0, + elapsed: 0, /** * The time taken to execute the test once (secs). @@ -2502,7 +2712,7 @@ module.exports = (function() { * @memberOf Benchmark#times * @type number */ - 'period': 0, + period: 0, /** * A timestamp of when the benchmark started (ms). @@ -2510,34 +2720,33 @@ module.exports = (function() { * @memberOf Benchmark#times * @type number */ - 'timeStamp': 0 - } + timeStamp: 0, + }, }); _.assign(Benchmark.prototype, { - 'abort': abort, - 'clone': clone, - 'compare': compare, - 'emit': emit, - 'listeners': listeners, - 'off': off, - 'on': on, - 'reset': reset, - 'run': run, - 'toString': toStringBench + abort: abort, + clone: clone, + compare: compare, + emit: emit, + listeners: listeners, + off: off, + on: on, + reset: reset, + run: run, + toString: toStringBench, }); /*------------------------------------------------------------------------*/ _.assign(Deferred.prototype, { - /** * The deferred benchmark instance. * * @memberOf Benchmark.Deferred * @type Object */ - 'benchmark': null, + benchmark: null, /** * The number of deferred cycles performed while benchmarking. @@ -2545,7 +2754,7 @@ module.exports = (function() { * @memberOf Benchmark.Deferred * @type number */ - 'cycles': 0, + cycles: 0, /** * The time taken to complete the deferred benchmark (secs). @@ -2553,7 +2762,7 @@ module.exports = (function() { * @memberOf Benchmark.Deferred * @type number */ - 'elapsed': 0, + elapsed: 0, /** * A timestamp of when the deferred benchmark started (ms). @@ -2561,24 +2770,23 @@ module.exports = (function() { * @memberOf Benchmark.Deferred * @type number */ - 'timeStamp': 0 + timeStamp: 0, }); _.assign(Deferred.prototype, { - 'resolve': resolve + resolve: resolve, }); /*------------------------------------------------------------------------*/ _.assign(Event.prototype, { - /** * A flag to indicate if the emitters listener iteration is aborted. * * @memberOf Benchmark.Event * @type boolean */ - 'aborted': false, + aborted: false, /** * A flag to indicate if the default action is cancelled. @@ -2586,7 +2794,7 @@ module.exports = (function() { * @memberOf Benchmark.Event * @type boolean */ - 'cancelled': false, + cancelled: false, /** * The object whose listeners are currently being processed. @@ -2594,7 +2802,7 @@ module.exports = (function() { * @memberOf Benchmark.Event * @type Object */ - 'currentTarget': undefined, + currentTarget: undefined, /** * The return value of the last executed listener. @@ -2602,7 +2810,7 @@ module.exports = (function() { * @memberOf Benchmark.Event * @type Mixed */ - 'result': undefined, + result: undefined, /** * The object to which the event was originally emitted. @@ -2610,7 +2818,7 @@ module.exports = (function() { * @memberOf Benchmark.Event * @type Object */ - 'target': undefined, + target: undefined, /** * A timestamp of when the event was created (ms). @@ -2618,7 +2826,7 @@ module.exports = (function() { * @memberOf Benchmark.Event * @type number */ - 'timeStamp': 0, + timeStamp: 0, /** * The event type. @@ -2626,7 +2834,7 @@ module.exports = (function() { * @memberOf Benchmark.Event * @type string */ - 'type': '' + type: '', }); /*------------------------------------------------------------------------*/ @@ -2639,27 +2847,25 @@ module.exports = (function() { * @type Object */ Suite.options = { - /** * The name of the suite. * * @memberOf Benchmark.Suite.options * @type string */ - 'name': undefined + name: undefined, }; /*------------------------------------------------------------------------*/ _.assign(Suite.prototype, { - /** * The number of benchmarks in the suite. * * @memberOf Benchmark.Suite * @type number */ - 'length': 0, + length: 0, /** * A flag to indicate if the suite is aborted. @@ -2667,7 +2873,7 @@ module.exports = (function() { * @memberOf Benchmark.Suite * @type boolean */ - 'aborted': false, + aborted: false, /** * A flag to indicate if the suite is running. @@ -2675,60 +2881,63 @@ module.exports = (function() { * @memberOf Benchmark.Suite * @type boolean */ - 'running': false + running: false, }); _.assign(Suite.prototype, { - 'abort': abortSuite, - 'add': add, - 'clone': cloneSuite, - 'emit': emit, - 'filter': filterSuite, - 'join': arrayRef.join, - 'listeners': listeners, - 'off': off, - 'on': on, - 'pop': arrayRef.pop, - 'push': push, - 'reset': resetSuite, - 'run': runSuite, - 'reverse': arrayRef.reverse, - 'shift': shift, - 'slice': slice, - 'sort': arrayRef.sort, - 'splice': arrayRef.splice, - 'unshift': unshift + abort: abortSuite, + add: add, + clone: cloneSuite, + emit: emit, + filter: filterSuite, + join: arrayRef.join, + listeners: listeners, + off: off, + on: on, + pop: arrayRef.pop, + push: push, + reset: resetSuite, + run: runSuite, + reverse: arrayRef.reverse, + shift: shift, + slice: slice, + sort: arrayRef.sort, + splice: arrayRef.splice, + unshift: unshift, }); /*------------------------------------------------------------------------*/ // Expose Deferred, Event, and Suite. _.assign(Benchmark, { - 'Deferred': Deferred, - 'Event': Event, - 'Suite': Suite + Deferred: Deferred, + Event: Event, + Suite: Suite, }); /*------------------------------------------------------------------------*/ // Add lodash methods as Suite methods. - _.each(['each', 'forEach', 'indexOf', 'map', 'reduce'], function(methodName) { - var func = _[methodName]; - Suite.prototype[methodName] = function() { - var args = [this]; - push.apply(args, arguments); - return func.apply(_, args); - }; - }); + _.each( + ['each', 'forEach', 'indexOf', 'map', 'reduce'], + function (methodName) { + var func = _[methodName]; + Suite.prototype[methodName] = function () { + var args = [this]; + push.apply(args, arguments); + return func.apply(_, args); + }; + }, + ); // Avoid array-like object bugs with `Array#shift` and `Array#splice` // in Firefox < 10 and IE < 9. - _.each(['pop', 'shift', 'splice'], function(methodName) { + _.each(['pop', 'shift', 'splice'], function (methodName) { var func = arrayRef[methodName]; - Suite.prototype[methodName] = function() { + Suite.prototype[methodName] = function () { var value = this, - result = func.apply(value, arguments); + result = func.apply(value, arguments); if (value.length === 0) { delete value[0]; @@ -2739,7 +2948,7 @@ module.exports = (function() { // Avoid buggy `Array#unshift` in IE < 8 which doesn't return the new // length of the array. - Suite.prototype.unshift = function() { + Suite.prototype.unshift = function () { var value = this; unshift.apply(value, arguments); return value.length; @@ -2755,5 +2964,4 @@ module.exports = (function() { window.Benchmark = Benchmark; return Benchmark; - -}.call(this)); +}.call(this); diff --git a/tgui/packages/tgui-bench/tests/Button.test.tsx b/tgui/packages/tgui-bench/tests/Button.test.tsx index e3472cbbbfae..6b806d720ab8 100644 --- a/tgui/packages/tgui-bench/tests/Button.test.tsx +++ b/tgui/packages/tgui-bench/tests/Button.test.tsx @@ -7,28 +7,18 @@ const render = createRenderer(); const handleClick = () => undefined; export const SingleButton = () => { - const node = ( - - ); + const node = ; render(node); }; export const SingleButtonWithCallback = () => { - const node = ( - - ); + const node = ; render(node); }; export const SingleButtonWithLinkEvent = () => { const node = ( - + ); render(node); }; @@ -36,11 +26,7 @@ export const SingleButtonWithLinkEvent = () => { export const ListOfButtons = () => { const nodes: JSX.Element[] = []; for (let i = 0; i < 100; i++) { - const node = ( - - ); + const node = ; nodes.push(node); } render(
{nodes}
); diff --git a/tgui/packages/tgui-bench/tests/DisposalUnit.test.tsx b/tgui/packages/tgui-bench/tests/DisposalUnit.test.tsx index b588f306f76a..3832d4fc9ca4 100644 --- a/tgui/packages/tgui-bench/tests/DisposalUnit.test.tsx +++ b/tgui/packages/tgui-bench/tests/DisposalUnit.test.tsx @@ -6,9 +6,11 @@ import { configureStore, StoreProvider } from 'tgui/store'; const store = configureStore({ sideEffets: false }); const renderUi = createRenderer((dataJson: string) => { - store.dispatch(backendUpdate({ - data: Byond.parseJson(dataJson), - })); + store.dispatch( + backendUpdate({ + data: Byond.parseJson(dataJson), + }), + ); return ( diff --git a/tgui/packages/tgui-bench/tests/Flex.test.tsx b/tgui/packages/tgui-bench/tests/Flex.test.tsx index e81ebc6f611b..66c039a19083 100644 --- a/tgui/packages/tgui-bench/tests/Flex.test.tsx +++ b/tgui/packages/tgui-bench/tests/Flex.test.tsx @@ -6,9 +6,7 @@ const render = createRenderer(); export const Default = () => { const node = ( - - Text {Math.random()} - + Text {Math.random()} Text {Math.random()} diff --git a/tgui/packages/tgui-bench/tests/Stack.test.tsx b/tgui/packages/tgui-bench/tests/Stack.test.tsx index 952dba20294e..ce7f5599e721 100644 --- a/tgui/packages/tgui-bench/tests/Stack.test.tsx +++ b/tgui/packages/tgui-bench/tests/Stack.test.tsx @@ -6,9 +6,7 @@ const render = createRenderer(); export const Default = () => { const node = ( - - Text {Math.random()} - + Text {Math.random()} Text {Math.random()} diff --git a/tgui/packages/tgui-bench/tests/Tooltip.test.tsx b/tgui/packages/tgui-bench/tests/Tooltip.test.tsx index b953fc911d22..9dae16f5c030 100644 --- a/tgui/packages/tgui-bench/tests/Tooltip.test.tsx +++ b/tgui/packages/tgui-bench/tests/Tooltip.test.tsx @@ -1,5 +1,5 @@ -import { Box, Tooltip } from "tgui/components"; -import { createRenderer } from "tgui/renderer"; +import { Box, Tooltip } from 'tgui/components'; +import { createRenderer } from 'tgui/renderer'; const render = createRenderer(); @@ -12,7 +12,7 @@ export const ListOfTooltips = () => { Tooltip #{i} - + , ); } diff --git a/tgui/packages/tgui-dev-server/dreamseeker.js b/tgui/packages/tgui-dev-server/dreamseeker.js index 21ad32e06451..fcb939e46cc0 100644 --- a/tgui/packages/tgui-dev-server/dreamseeker.js +++ b/tgui/packages/tgui-dev-server/dreamseeker.js @@ -25,11 +25,13 @@ export class DreamSeeker { topic(params = {}) { const query = Object.keys(params) - .map(key => encodeURIComponent(key) - + '=' + encodeURIComponent(params[key])) + .map( + (key) => + encodeURIComponent(key) + '=' + encodeURIComponent(params[key]), + ) .join('&'); logger.log( - `topic call at ${this.client.defaults.baseURL + '/dummy?' + query}` + `topic call at ${this.client.defaults.baseURL + '/dummy?' + query}`, ); return this.client.get('/dummy?' + query); } @@ -39,7 +41,7 @@ export class DreamSeeker { * @param {number[]} pids * @returns {DreamSeeker[]} */ -DreamSeeker.getInstancesByPids = async pids => { +DreamSeeker.getInstancesByPids = async (pids) => { if (process.platform !== 'win32') { return []; } @@ -49,8 +51,7 @@ DreamSeeker.getInstancesByPids = async pids => { const instance = instanceByPid.get(pid); if (instance) { instances.push(instance); - } - else { + } else { pidsToResolve.push(pid); } } @@ -86,12 +87,10 @@ DreamSeeker.getInstancesByPids = async pids => { instances.push(instance); instanceByPid.set(pid, instance); } - } - catch (err) { + } catch (err) { if (err.code === 'ERR_CHILD_PROCESS_STDIO_MAXBUFFER') { logger.error(err.message, err.code); - } - else { + } else { logger.error(err); } return []; @@ -100,4 +99,4 @@ DreamSeeker.getInstancesByPids = async pids => { return instances; }; -const plural = (word, n) => n !== 1 ? word + 's' : word; +const plural = (word, n) => (n !== 1 ? word + 's' : word); diff --git a/tgui/packages/tgui-dev-server/link/client.cjs b/tgui/packages/tgui-dev-server/link/client.cjs index fe75314acd3a..a4f703aee68a 100644 --- a/tgui/packages/tgui-dev-server/link/client.cjs +++ b/tgui/packages/tgui-dev-server/link/client.cjs @@ -23,7 +23,7 @@ const ensureConnection = () => { socket.send(msg); } }; - socket.onmessage = event => { + socket.onmessage = (event) => { const msg = JSON.parse(event.data); for (let subscriber of subscribers) { subscriber(msg); @@ -37,14 +37,14 @@ if (process.env.NODE_ENV !== 'production') { window.onunload = () => socket && socket.close(); } -const subscribe = fn => subscribers.push(fn); +const subscribe = (fn) => subscribers.push(fn); /** * A json serializer which handles circular references and other junk. */ -const serializeObject = obj => { +const serializeObject = (obj) => { let refs = []; - const primitiveReviver = value => { + const primitiveReviver = (value) => { if (typeof value === 'number' && !Number.isFinite(value)) { return { __number__: String(value), @@ -68,9 +68,9 @@ const serializeObject = obj => { } refs.push(value); // Error object - const isError = value instanceof Error || ( - value.code && value.message && value.message.includes('Error') - ); + const isError = + value instanceof Error || + (value.code && value.message && value.message.includes('Error')); if (isError) { return { __error__: true, @@ -91,7 +91,7 @@ const serializeObject = obj => { return json; }; -const sendMessage = msg => { +const sendMessage = (msg) => { if (process.env.NODE_ENV !== 'production') { const json = serializeObject(msg); // Send message using WebSocket @@ -99,8 +99,7 @@ const sendMessage = msg => { ensureConnection(); if (socket.readyState === WebSocket.OPEN) { socket.send(json); - } - else { + } else { // Keep only 100 latest messages in the queue if (queue.length > 100) { queue.shift(); @@ -130,19 +129,20 @@ const sendLogEntry = (level, ns, ...args) => { args, }, }); - } - catch (err) {} + } catch (err) {} } }; const setupHotReloading = () => { - if (process.env.NODE_ENV !== 'production' - && process.env.WEBPACK_HMR_ENABLED - && window.WebSocket) { + if ( + process.env.NODE_ENV !== 'production' && + process.env.WEBPACK_HMR_ENABLED && + window.WebSocket + ) { if (module.hot) { ensureConnection(); sendLogEntry(0, null, 'setting up hot reloading'); - subscribe(msg => { + subscribe((msg) => { const { type } = msg; sendLogEntry(0, null, 'received', type); if (type === 'hotUpdate') { @@ -157,10 +157,10 @@ const setupHotReloading = () => { ignoreDeclined: true, ignoreErrored: true, }) - .then(modules => { + .then((modules) => { sendLogEntry(0, null, 'outdated modules', modules); }) - .catch(err => { + .catch((err) => { sendLogEntry(0, null, 'reload error', err); }); } diff --git a/tgui/packages/tgui-dev-server/link/retrace.js b/tgui/packages/tgui-dev-server/link/retrace.js index c10ba9cb173c..b7f4d4eacfb9 100644 --- a/tgui/packages/tgui-dev-server/link/retrace.js +++ b/tgui/packages/tgui-dev-server/link/retrace.js @@ -18,7 +18,7 @@ const logger = createLogger('retrace'); const { SourceMapConsumer } = SourceMap; const sourceMaps = []; -export const loadSourceMaps = async bundleDir => { +export const loadSourceMaps = async (bundleDir) => { // Destroy and garbage collect consumers while (sourceMaps.length !== 0) { const { consumer } = sourceMaps.shift(); @@ -30,29 +30,29 @@ export const loadSourceMaps = async bundleDir => { try { const file = basename(path).replace('.map', ''); const consumer = await new SourceMapConsumer( - JSON.parse(fs.readFileSync(path, 'utf8'))); + JSON.parse(fs.readFileSync(path, 'utf8')), + ); sourceMaps.push({ file, consumer }); - } - catch (err) { + } catch (err) { logger.error(err); } } logger.log(`loaded ${sourceMaps.length} source maps`); }; -export const retrace = stack => { +export const retrace = (stack) => { if (typeof stack !== 'string') { logger.log('ERROR: Stack is not a string!', stack); return stack; } const header = stack.split(/\n\s.*at/)[0]; const mappedStack = parseStackTrace(stack) - .map(frame => { + .map((frame) => { if (!frame.file) { return frame; } // Find the correct source map - const sourceMap = sourceMaps.find(sourceMap => { + const sourceMap = sourceMaps.find((sourceMap) => { return frame.file.includes(sourceMap.file); }); if (!sourceMap) { @@ -72,7 +72,7 @@ export const retrace = stack => { column: mappedFrame.column, }; }) - .map(frame => { + .map((frame) => { // Stringify the frame const { file, methodName, lineNumber } = frame; if (!file) { diff --git a/tgui/packages/tgui-dev-server/link/server.js b/tgui/packages/tgui-dev-server/link/server.js index 87a8a5911bc0..81ede9e6efc2 100644 --- a/tgui/packages/tgui-dev-server/link/server.js +++ b/tgui/packages/tgui-dev-server/link/server.js @@ -32,9 +32,9 @@ class LinkServer { setupWebSocketLink() { const port = 3000; this.wss = new WebSocket.Server({ port }); - this.wss.on('connection', ws => { + this.wss.on('connection', (ws) => { logger.log('client connected'); - ws.on('message', json => { + ws.on('message', (json) => { const msg = deserializeObject(json); this.handleLinkMessage(ws, msg); }); @@ -51,7 +51,7 @@ class LinkServer { this.httpServer = http.createServer((req, res) => { if (req.method === 'POST') { let body = ''; - req.on('data', chunk => { + req.on('data', (chunk) => { body += chunk.toString(); }); req.on('end', () => { @@ -76,16 +76,19 @@ class LinkServer { if (level <= 0 && !DEBUG) { return; } - directLog(ns, ...args.map(arg => { - if (typeof arg === 'object') { - return inspect(arg, { - depth: Infinity, - colors: true, - compact: 8, - }); - } - return arg; - })); + directLog( + ns, + ...args.map((arg) => { + if (typeof arg === 'object') { + return inspect(arg, { + depth: Infinity, + colors: true, + compact: 8, + }); + } + return arg; + }), + ); return; } if (type === 'relay') { @@ -117,7 +120,7 @@ class LinkServer { } } -const deserializeObject = str => { +const deserializeObject = (str) => { return JSON.parse(str, (key, value) => { if (typeof value === 'object' && value !== null) { if (value.__undefined__) { diff --git a/tgui/packages/tgui-dev-server/logging.js b/tgui/packages/tgui-dev-server/logging.js index 0dc222ae3d73..143c96b97aba 100644 --- a/tgui/packages/tgui-dev-server/logging.js +++ b/tgui/packages/tgui-dev-server/logging.js @@ -11,8 +11,7 @@ const isNode = process && process.release && process.release.name === 'node'; let isChrome = false; try { isChrome = window.navigator.userAgent.toLowerCase().includes('chrome'); -} -catch {} +} catch {} // Timestamping function const getTimestamp = () => { @@ -32,7 +31,7 @@ const getPrefix = (() => { bright: '\x1b[37;1m', reset: '\x1b[0m', }; - return ns => [ + return (ns) => [ `${ESC.dimmed}${getTimestamp()} ${ESC.bright}${ns}${ESC.reset}`, ]; } @@ -42,21 +41,19 @@ const getPrefix = (() => { dimmed: 'color: #888', bright: 'font-weight: bold', }; - return ns => [ + return (ns) => [ `%c${getTimestamp()}%c ${ns}`, styles.dimmed, styles.bright, ]; } - return ns => [ - `${getTimestamp()} ${ns}`, - ]; + return (ns) => [`${getTimestamp()} ${ns}`]; })(); /** * Creates a logger object. */ -export const createLogger = ns => ({ +export const createLogger = (ns) => ({ log: (...args) => console.log(...getPrefix(ns), ...args), trace: (...args) => console.trace(...getPrefix(ns), ...args), debug: (...args) => console.debug(...getPrefix(ns), ...args), diff --git a/tgui/packages/tgui-dev-server/reloader.js b/tgui/packages/tgui-dev-server/reloader.js index f130093badbb..91c5e6c90e4f 100644 --- a/tgui/packages/tgui-dev-server/reloader.js +++ b/tgui/packages/tgui-dev-server/reloader.js @@ -50,14 +50,9 @@ export const findCacheRoot = async () => { // Query the Windows Registry if (process.platform === 'win32') { logger.log('querying windows registry'); - let userpath = await regQuery( - 'HKCU\\Software\\Dantom\\BYOND', - 'userpath'); + let userpath = await regQuery('HKCU\\Software\\Dantom\\BYOND', 'userpath'); if (userpath) { - cacheRoot = userpath - .replace(/\\$/, '') - .replace(/\\/g, '/') - + '/cache'; + cacheRoot = userpath.replace(/\\$/, '').replace(/\\/g, '/') + '/cache'; onCacheRootFound(cacheRoot); return cacheRoot; } @@ -65,13 +60,13 @@ export const findCacheRoot = async () => { logger.log('found no cache directories'); }; -const onCacheRootFound = cacheRoot => { +const onCacheRootFound = (cacheRoot) => { logger.log(`found cache at '${cacheRoot}'`); // Plant a dummy browser window file, byond 514 stuff. fs.closeSync(fs.openSync(cacheRoot + '/dummy', 'w')); }; -export const reloadByondCache = async bundleDir => { +export const reloadByondCache = async (bundleDir) => { const cacheRoot = await findCacheRoot(); if (!cacheRoot) { return; @@ -83,15 +78,21 @@ export const reloadByondCache = async bundleDir => { return; } // Get dreamseeker instances - const pids = cacheDirs.map(cacheDir => ( - parseInt(cacheDir.split('/cache/tmp').pop(), 10) - )); + const pids = cacheDirs.map((cacheDir) => + parseInt(cacheDir.split('/cache/tmp').pop(), 10), + ); const dssPromise = DreamSeeker.getInstancesByPids(pids); // Copy assets - const assets = await resolveGlob(bundleDir, './*.+(bundle|chunk|hot-update).*'); + const assets = await resolveGlob( + bundleDir, + './*.+(bundle|chunk|hot-update).*', + ); for (let cacheDir of cacheDirs) { // Clear garbage - const garbage = await resolveGlob(cacheDir, './*.+(bundle|chunk|hot-update).*'); + const garbage = await resolveGlob( + cacheDir, + './*.+(bundle|chunk|hot-update).*', + ); try { // Plant a dummy browser window file // we'll be using this to avoid world topic for 515 @@ -105,8 +106,7 @@ export const reloadByondCache = async bundleDir => { fs.writeFileSync(destination, fs.readFileSync(asset)); } logger.log(`copied ${assets.length} files to '${cacheDir}'`); - } - catch (err) { + } catch (err) { logger.error(`failed copying to '${cacheDir}'`); logger.error(err); } diff --git a/tgui/packages/tgui-dev-server/util.js b/tgui/packages/tgui-dev-server/util.js index 0fc255ed6744..9d07b96c71a0 100644 --- a/tgui/packages/tgui-dev-server/util.js +++ b/tgui/packages/tgui-dev-server/util.js @@ -25,8 +25,7 @@ export const resolveGlob = (...sections) => { try { fs.statSync(path); safePaths.push(path); - } - catch {} + } catch {} } return safePaths; }; diff --git a/tgui/packages/tgui-dev-server/webpack.js b/tgui/packages/tgui-dev-server/webpack.js index 8cba68afcba5..139610b79ce9 100644 --- a/tgui/packages/tgui-dev-server/webpack.js +++ b/tgui/packages/tgui-dev-server/webpack.js @@ -18,7 +18,7 @@ const logger = createLogger('webpack'); * @param {any} config * @return {WebpackCompiler} */ -export const createCompiler = async options => { +export const createCompiler = async (options) => { const compiler = new WebpackCompiler(); await compiler.setup(options); return compiler; @@ -57,7 +57,7 @@ class WebpackCompiler { logger.log('compiling'); }); // Start reloading when it's finished - compiler.hooks.done.tap('tgui-dev-server', async stats => { + compiler.hooks.done.tap('tgui-dev-server', async (stats) => { // Load source maps await loadSourceMaps(this.bundleDir); // Reload cache @@ -77,7 +77,7 @@ class WebpackCompiler { stats .toString(this.config.devServer.stats) .split('\n') - .forEach(line => logger.log(line)); + .forEach((line) => logger.log(line)); }); } } diff --git a/tgui/packages/tgui-dev-server/winreg.js b/tgui/packages/tgui-dev-server/winreg.js index 669e2aad55d6..b61fddc1a255 100644 --- a/tgui/packages/tgui-dev-server/winreg.js +++ b/tgui/packages/tgui-dev-server/winreg.js @@ -30,17 +30,14 @@ export const regQuery = async (path, key) => { logger.error('could not find the end of the line'); return null; } - const indexOfValue = stdout.indexOf( - ' ', - indexOfKey + keyPattern.length); + const indexOfValue = stdout.indexOf(' ', indexOfKey + keyPattern.length); if (indexOfValue === -1) { logger.error('could not find the start of the key value'); return null; } const value = stdout.substring(indexOfValue + 4, indexOfEol); return value; - } - catch (err) { + } catch (err) { logger.error(err); return null; } diff --git a/tgui/packages/tgui-panel/Notifications.js b/tgui/packages/tgui-panel/Notifications.js index a64ddd8e306e..2b92995287fa 100644 --- a/tgui/packages/tgui-panel/Notifications.js +++ b/tgui/packages/tgui-panel/Notifications.js @@ -6,33 +6,20 @@ import { Flex } from 'tgui/components'; -export const Notifications = props => { +export const Notifications = (props) => { const { children } = props; - return ( -
- {children} -
- ); + return
{children}
; }; -const NotificationsItem = props => { - const { - rightSlot, - children, - } = props; +const NotificationsItem = (props) => { + const { rightSlot, children } = props; return ( - - + + {children} {rightSlot && ( - - {rightSlot} - + {rightSlot} )} ); diff --git a/tgui/packages/tgui-panel/Panel.js b/tgui/packages/tgui-panel/Panel.js index a09875e9b2f3..18976735de9e 100644 --- a/tgui/packages/tgui-panel/Panel.js +++ b/tgui/packages/tgui-panel/Panel.js @@ -17,9 +17,7 @@ import { SettingsPanel, useSettings } from './settings'; export const Panel = (props, context) => { // IE8-10: Needs special treatment due to missing Flex support if (Byond.IS_LTE_IE10) { - return ( - - ); + return ; } const audio = useAudio(context); const settings = useSettings(context); @@ -28,9 +26,7 @@ export const Panel = (props, context) => { const { useDebug, KitchenSink } = require('tgui/debug'); const debug = useDebug(context); if (debug.kitchenSink) { - return ( - - ); + return ; } } return ( @@ -52,17 +48,19 @@ export const Panel = (props, context) => { icon="music" tooltip="Music player" tooltipPosition="bottom-start" - onClick={() => audio.toggle()} /> + onClick={() => audio.toggle()} + /> - {settings.visible && ( - - ) || ( + {(settings.visible && ) || ( )} diff --git a/tgui/packages/tgui-panel/audio/NowPlayingWidget.js b/tgui/packages/tgui-panel/audio/NowPlayingWidget.js index e4fe04eed167..cbf7ad9482f8 100644 --- a/tgui/packages/tgui-panel/audio/NowPlayingWidget.js +++ b/tgui/packages/tgui-panel/audio/NowPlayingWidget.js @@ -17,12 +17,9 @@ export const NowPlayingWidget = (props, context) => { const title = audio.meta?.title; return ( - {audio.playing && ( + {(audio.playing && ( <> - + Now playing: { grow={1} style={{ 'white-space': 'nowrap', - 'overflow': 'hidden', + overflow: 'hidden', 'text-overflow': 'ellipsis', - }}> + }} + > {title || 'Unknown Track'} - ) || ( + )) || ( Nothing to play. @@ -46,9 +44,12 @@ export const NowPlayingWidget = (props, context) => {
- {MESSAGE_TYPES - .filter(typeDef => !typeDef.important && !typeDef.admin) - .map(typeDef => ( + {MESSAGE_TYPES.filter( + (typeDef) => !typeDef.important && !typeDef.admin, + ).map((typeDef) => ( + + dispatch( + toggleAcceptedType({ + pageId: page.id, + type: typeDef.type, + }), + ) + } + > + {typeDef.name} + + ))} + + {MESSAGE_TYPES.filter( + (typeDef) => !typeDef.important && typeDef.admin, + ).map((typeDef) => ( dispatch(toggleAcceptedType({ - pageId: page.id, - type: typeDef.type, - }))}> + onClick={() => + dispatch( + toggleAcceptedType({ + pageId: page.id, + type: typeDef.type, + }), + ) + } + > {typeDef.name} ))} - - {MESSAGE_TYPES - .filter(typeDef => !typeDef.important && typeDef.admin) - .map(typeDef => ( - dispatch(toggleAcceptedType({ - pageId: page.id, - type: typeDef.type, - }))}> - {typeDef.name} - - ))}
diff --git a/tgui/packages/tgui-panel/chat/ChatPanel.js b/tgui/packages/tgui-panel/chat/ChatPanel.js index 0a5deaf9febe..1577e933fb4c 100644 --- a/tgui/packages/tgui-panel/chat/ChatPanel.js +++ b/tgui/packages/tgui-panel/chat/ChatPanel.js @@ -16,33 +16,37 @@ export class ChatPanel extends Component { this.state = { scrollTracking: true, }; - this.handleScrollTrackingChange = value => this.setState({ - scrollTracking: value, - }); + this.handleScrollTrackingChange = (value) => + this.setState({ + scrollTracking: value, + }); } componentDidMount() { chatRenderer.mount(this.ref.current); - chatRenderer.events.on('scrollTrackingChanged', - this.handleScrollTrackingChange); + chatRenderer.events.on( + 'scrollTrackingChanged', + this.handleScrollTrackingChange, + ); this.componentDidUpdate(); } componentWillUnmount() { - chatRenderer.events.off('scrollTrackingChanged', - this.handleScrollTrackingChange); + chatRenderer.events.off( + 'scrollTrackingChanged', + this.handleScrollTrackingChange, + ); } componentDidUpdate(prevProps) { requestAnimationFrame(() => { chatRenderer.ensureScrollTracking(); }); - const shouldUpdateStyle = ( - !prevProps || shallowDiffers(this.props, prevProps) - ); + const shouldUpdateStyle = + !prevProps || shallowDiffers(this.props, prevProps); if (shouldUpdateStyle) { chatRenderer.assignStyle({ - 'width': '100%', + width: '100%', 'white-space': 'pre-wrap', 'font-size': this.props.fontSize, 'line-height': this.props.lineHeight, @@ -51,9 +55,7 @@ export class ChatPanel extends Component { } render() { - const { - scrollTracking, - } = this.state; + const { scrollTracking } = this.state; return ( <>
@@ -61,7 +63,8 @@ export class ChatPanel extends Component { )} diff --git a/tgui/packages/tgui-panel/chat/ChatTabs.js b/tgui/packages/tgui-panel/chat/ChatTabs.js index a0e6cc59e523..601cd111589e 100644 --- a/tgui/packages/tgui-panel/chat/ChatTabs.js +++ b/tgui/packages/tgui-panel/chat/ChatTabs.js @@ -15,11 +15,12 @@ const UnreadCountWidget = ({ value }) => ( style={{ 'font-size': '0.7em', 'border-radius': '0.25em', - 'width': '1.7em', + width: '1.7em', 'line-height': '1.55em', 'background-color': 'crimson', - 'color': '#fff', - }}> + color: '#fff', + }} + > {Math.min(value, 99)} ); @@ -32,16 +33,23 @@ export const ChatTabs = (props, context) => { - {pages.map(page => ( + {pages.map((page) => ( 0 && ( - - )} - onClick={() => dispatch(changeChatPage({ - pageId: page.id, - }))}> + rightSlot={ + page.unreadCount > 0 && ( + + ) + } + onClick={() => + dispatch( + changeChatPage({ + pageId: page.id, + }), + ) + } + > {page.name} ))} @@ -54,7 +62,8 @@ export const ChatTabs = (props, context) => { onClick={() => { dispatch(addChatPage()); dispatch(openChatSettings()); - }} /> + }} + /> ); diff --git a/tgui/packages/tgui-panel/chat/constants.js b/tgui/packages/tgui-panel/chat/constants.js index 0333b6489991..97a607eac305 100644 --- a/tgui/packages/tgui-panel/chat/constants.js +++ b/tgui/packages/tgui-panel/chat/constants.js @@ -58,19 +58,22 @@ export const MESSAGE_TYPES = [ type: MESSAGE_TYPE_RADIO, name: 'Radio', description: 'All departments of radio messages', - selector: '.alert, .minorannounce, .syndradio, .centcomradio, .aiprivradio, .comradio, .secradio, .gangradio, .engradio, .medradio, .sciradio, .suppradio, .servradio, .radio, .deptradio, .binarysay, .newscaster, .resonate', + selector: + '.alert, .minorannounce, .syndradio, .centcomradio, .aiprivradio, .comradio, .secradio, .gangradio, .engradio, .medradio, .sciradio, .suppradio, .servradio, .radio, .deptradio, .binarysay, .newscaster, .resonate', }, { type: MESSAGE_TYPE_INFO, name: 'Info', description: 'Non-urgent messages from the game and items', - selector: '.notice:not(.pm), .adminnotice, .info, .sinister, .cult, .infoplain, .announce, .hear, .smallnotice, .holoparasite, .boldnotice', + selector: + '.notice:not(.pm), .adminnotice, .info, .sinister, .cult, .infoplain, .announce, .hear, .smallnotice, .holoparasite, .boldnotice', }, { type: MESSAGE_TYPE_WARNING, name: 'Warnings', description: 'Urgent messages from the game and items', - selector: '.warning:not(.pm), .critical, .userdanger, .italics, .alertsyndie, .warningplain', + selector: + '.warning:not(.pm), .critical, .userdanger, .italics, .alertsyndie, .warningplain', }, { type: MESSAGE_TYPE_DEADCHAT, diff --git a/tgui/packages/tgui-panel/chat/middleware.js b/tgui/packages/tgui-panel/chat/middleware.js index 6cfc72bd2994..1556969677b4 100644 --- a/tgui/packages/tgui-panel/chat/middleware.js +++ b/tgui/packages/tgui-panel/chat/middleware.js @@ -8,32 +8,39 @@ import DOMPurify from 'dompurify'; import { storage } from 'common/storage'; import { loadSettings, updateSettings } from '../settings/actions'; import { selectSettings } from '../settings/selectors'; -import { addChatPage, changeChatPage, changeScrollTracking, loadChat, rebuildChat, removeChatPage, saveChatToDisk, toggleAcceptedType, updateMessageCount } from './actions'; +import { + addChatPage, + changeChatPage, + changeScrollTracking, + loadChat, + rebuildChat, + removeChatPage, + saveChatToDisk, + toggleAcceptedType, + updateMessageCount, +} from './actions'; import { MAX_PERSISTED_MESSAGES, MESSAGE_SAVE_INTERVAL } from './constants'; import { createMessage, serializeMessage } from './model'; import { chatRenderer } from './renderer'; import { selectChat, selectCurrentChatPage } from './selectors'; // List of blacklisted tags -const FORBID_TAGS = [ - 'a', - 'iframe', - 'link', - 'video', -]; +const FORBID_TAGS = ['a', 'iframe', 'link', 'video']; -const saveChatToStorage = async store => { +const saveChatToStorage = async (store) => { const state = selectChat(store.getState()); - const fromIndex = Math.max(0, - chatRenderer.messages.length - MAX_PERSISTED_MESSAGES); + const fromIndex = Math.max( + 0, + chatRenderer.messages.length - MAX_PERSISTED_MESSAGES, + ); const messages = chatRenderer.messages .slice(fromIndex) - .map(message => serializeMessage(message)); + .map((message) => serializeMessage(message)); storage.set('chat-state', state); storage.set('chat-messages', messages); }; -const loadChatFromStorage = async store => { +const loadChatFromStorage = async (store) => { const [state, messages] = await Promise.all([ storage.get('chat-state'), storage.get('chat-messages'), @@ -64,10 +71,10 @@ const loadChatFromStorage = async store => { store.dispatch(loadChat(state)); }; -export const chatMiddleware = store => { +export const chatMiddleware = (store) => { let initialized = false; let loaded = false; - chatRenderer.events.on('batchProcessed', countByType => { + chatRenderer.events.on('batchProcessed', (countByType) => { // Use this flag to workaround unread messages caused by // loading them from storage. Side effect of that, is that // message count can not be trusted, only unread count. @@ -75,11 +82,11 @@ export const chatMiddleware = store => { store.dispatch(updateMessageCount(countByType)); } }); - chatRenderer.events.on('scrollTrackingChanged', scrollTracking => { + chatRenderer.events.on('scrollTrackingChanged', (scrollTracking) => { store.dispatch(changeScrollTracking(scrollTracking)); }); setInterval(() => saveChatToStorage(store), MESSAGE_SAVE_INTERVAL); - return next => action => { + return (next) => (action) => { const { type, payload } = action; if (!initialized) { initialized = true; @@ -99,10 +106,12 @@ export const chatMiddleware = store => { loaded = true; return; } - if (type === changeChatPage.type - || type === addChatPage.type - || type === removeChatPage.type - || type === toggleAcceptedType.type) { + if ( + type === changeChatPage.type || + type === addChatPage.type || + type === removeChatPage.type || + type === toggleAcceptedType.type + ) { next(action); const page = selectCurrentChatPage(store.getState()); chatRenderer.changePage(page); @@ -119,7 +128,8 @@ export const chatMiddleware = store => { settings.highlightText, settings.highlightColor, settings.matchWord, - settings.matchCase); + settings.matchCase, + ); return; } if (type === 'roundrestart') { diff --git a/tgui/packages/tgui-panel/chat/model.js b/tgui/packages/tgui-panel/chat/model.js index 7400d5e13cd3..fa12153890d8 100644 --- a/tgui/packages/tgui-panel/chat/model.js +++ b/tgui/packages/tgui-panel/chat/model.js @@ -7,11 +7,10 @@ import { createUuid } from 'common/uuid'; import { MESSAGE_TYPES, MESSAGE_TYPE_INTERNAL } from './constants'; -export const canPageAcceptType = (page, type) => ( - type.startsWith(MESSAGE_TYPE_INTERNAL) || page.acceptedTypes[type] -); +export const canPageAcceptType = (page, type) => + type.startsWith(MESSAGE_TYPE_INTERNAL) || page.acceptedTypes[type]; -export const createPage = obj => { +export const createPage = (obj) => { let acceptedTypes = {}; for (let typeDef of MESSAGE_TYPES) { @@ -39,12 +38,12 @@ export const createMainPage = () => { }); }; -export const createMessage = payload => ({ +export const createMessage = (payload) => ({ createdAt: Date.now(), ...payload, }); -export const serializeMessage = message => ({ +export const serializeMessage = (message) => ({ type: message.type, text: message.text, html: message.html, @@ -52,7 +51,6 @@ export const serializeMessage = message => ({ createdAt: message.createdAt, }); -export const isSameMessage = (a, b) => ( - typeof a.text === 'string' && a.text === b.text - || typeof a.html === 'string' && a.html === b.html -); +export const isSameMessage = (a, b) => + (typeof a.text === 'string' && a.text === b.text) || + (typeof a.html === 'string' && a.html === b.html); diff --git a/tgui/packages/tgui-panel/chat/reducer.js b/tgui/packages/tgui-panel/chat/reducer.js index 0188b1fabe8b..e75fbd06e43e 100644 --- a/tgui/packages/tgui-panel/chat/reducer.js +++ b/tgui/packages/tgui-panel/chat/reducer.js @@ -4,7 +4,16 @@ * @license MIT */ -import { addChatPage, changeChatPage, loadChat, removeChatPage, toggleAcceptedType, updateChatPage, updateMessageCount, changeScrollTracking } from './actions'; +import { + addChatPage, + changeChatPage, + loadChat, + removeChatPage, + toggleAcceptedType, + updateChatPage, + updateMessageCount, + changeScrollTracking, +} from './actions'; import { canPageAcceptType, createMainPage } from './model'; const mainPage = createMainPage(); @@ -13,9 +22,7 @@ export const initialState = { version: 5, currentPageId: mainPage.id, scrollTracking: true, - pages: [ - mainPage.id, - ], + pages: [mainPage.id], pageById: { [mainPage.id]: mainPage, }, @@ -74,7 +81,7 @@ export const chatReducer = (state = initialState, action) => { } if (type === updateMessageCount.type) { const countByType = payload; - const pages = state.pages.map(id => state.pageById[id]); + const pages = state.pages.map((id) => state.pageById[id]); const currentPage = state.pageById[state.currentPageId]; const nextPageById = { ...state.pageById }; for (let page of pages) { @@ -170,7 +177,7 @@ export const chatReducer = (state = initialState, action) => { }, }; delete nextState.pageById[pageId]; - nextState.pages = nextState.pages.filter(id => id !== pageId); + nextState.pages = nextState.pages.filter((id) => id !== pageId); if (nextState.pages.length === 0) { nextState.pages.push(mainPage.id); nextState.pageById[mainPage.id] = mainPage; diff --git a/tgui/packages/tgui-panel/chat/renderer.js b/tgui/packages/tgui-panel/chat/renderer.js index d99d0dbc445f..969f8ad93263 100644 --- a/tgui/packages/tgui-panel/chat/renderer.js +++ b/tgui/packages/tgui-panel/chat/renderer.js @@ -7,11 +7,25 @@ import { EventEmitter } from 'common/events'; import { classes } from 'common/react'; import { createLogger } from 'tgui/logging'; -import { COMBINE_MAX_MESSAGES, COMBINE_MAX_TIME_WINDOW, IMAGE_RETRY_DELAY, IMAGE_RETRY_LIMIT, IMAGE_RETRY_MESSAGE_AGE, MAX_PERSISTED_MESSAGES, MAX_VISIBLE_MESSAGES, MESSAGE_PRUNE_INTERVAL, MESSAGE_TYPES, MESSAGE_TYPE_COMBAT, MESSAGE_TYPE_INTERNAL, MESSAGE_TYPE_LOCALCHAT, MESSAGE_TYPE_UNKNOWN } from './constants'; +import { + COMBINE_MAX_MESSAGES, + COMBINE_MAX_TIME_WINDOW, + IMAGE_RETRY_DELAY, + IMAGE_RETRY_LIMIT, + IMAGE_RETRY_MESSAGE_AGE, + MAX_PERSISTED_MESSAGES, + MAX_VISIBLE_MESSAGES, + MESSAGE_PRUNE_INTERVAL, + MESSAGE_TYPES, + MESSAGE_TYPE_COMBAT, + MESSAGE_TYPE_INTERNAL, + MESSAGE_TYPE_LOCALCHAT, + MESSAGE_TYPE_UNKNOWN, +} from './constants'; import { render } from 'inferno'; import { canPageAcceptType, createMessage, isSameMessage } from './model'; import { highlightNode, linkifyNode } from './replaceInTextNode'; -import { Tooltip } from "../../tgui/components"; +import { Tooltip } from '../../tgui/components'; const logger = createLogger('chatRenderer'); @@ -27,11 +41,11 @@ export const TGUI_CHAT_COMPONENTS = { // List of injectable attibute names mapped to their proper prop // We need this because attibutes don't support lowercase names export const TGUI_CHAT_ATTRIBUTES_TO_PROPS = { - "position": "position", - "content": "content", + position: 'position', + content: 'content', }; -const findNearestScrollableParent = startingNode => { +const findNearestScrollableParent = (startingNode) => { const body = document.body; let node = startingNode; while (node && node !== body) { @@ -66,7 +80,7 @@ const createReconnectedNode = () => { return node; }; -const handleImageError = e => { +const handleImageError = (e) => { setTimeout(() => { /** @type {HTMLImageElement} */ const node = e.target; @@ -85,7 +99,7 @@ const handleImageError = e => { /** * Assigns a "times-repeated" badge to the message. */ -const updateMessageBadge = message => { +const updateMessageBadge = (message) => { const { node, times } = message; if (!node || !times) { // Nothing to update @@ -94,10 +108,7 @@ const updateMessageBadge = message => { const foundBadge = node.querySelector('.Chat__badge'); const badge = foundBadge || document.createElement('div'); badge.textContent = times; - badge.className = classes([ - 'Chat__badge', - 'Chat__badge--animate', - ]); + badge.className = classes(['Chat__badge', 'Chat__badge--animate']); requestAnimationFrame(() => { badge.className = 'Chat__badge'; }); @@ -121,13 +132,12 @@ class ChatRenderer { /** @type {HTMLElement} */ this.scrollNode = null; this.scrollTracking = true; - this.handleScroll = type => { + this.handleScroll = (type) => { const node = this.scrollNode; const height = node.scrollHeight; const bottom = node.scrollTop + node.offsetHeight; - const scrollTracking = ( - Math.abs(height - bottom) < SCROLL_TRACKING_TOLERANCE - ); + const scrollTracking = + Math.abs(height - bottom) < SCROLL_TRACKING_TOLERANCE; if (scrollTracking !== this.scrollTracking) { this.scrollTracking = scrollTracking; this.events.emit('scrollTrackingChanged', scrollTracking); @@ -193,18 +203,19 @@ class ChatRenderer { const lines = String(text) .split(',') // eslint-disable-next-line no-useless-escape - .map(str => str.trim().replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')) - .filter(str => ( - // Must be longer than one character - str && str.length > 1 - )); + .map((str) => str.trim().replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')) + .filter( + (str) => + // Must be longer than one character + str && str.length > 1, + ); // Nothing to match, reset highlighting if (lines.length === 0) { this.highlightRegex = null; this.highlightColor = null; return; } - const pattern = `${(matchWord ? '\\b' : '')}(${lines.join('|')})${(matchWord ? '\\b' : '')}`; + const pattern = `${matchWord ? '\\b' : ''}(${lines.join('|')})${matchWord ? '\\b' : ''}`; const flags = 'g' + (matchCase ? '' : 'i'); this.highlightRegex = new RegExp(pattern, flags); this.highlightColor = color; @@ -249,14 +260,13 @@ class ChatRenderer { const to = Math.max(0, len - COMBINE_MAX_MESSAGES); for (let i = from; i >= to; i--) { const message = this.visibleMessages[i]; - const matches = ( + const matches = // Is not an internal message - !message.type.startsWith(MESSAGE_TYPE_INTERNAL) + !message.type.startsWith(MESSAGE_TYPE_INTERNAL) && // Text payload must fully match - && isSameMessage(message, predicate) + isSameMessage(message, predicate) && // Must land within the specified time window - && now < message.createdAt + COMBINE_MAX_TIME_WINDOW - ); + now < message.createdAt + COMBINE_MAX_TIME_WINDOW; if (matches) { return message; } @@ -265,17 +275,13 @@ class ChatRenderer { } processBatch(batch, options = {}) { - const { - prepend, - notifyListeners = true, - } = options; + const { prepend, notifyListeners = true } = options; const now = Date.now(); // Queue up messages until chat is ready if (!this.isReady()) { if (prepend) { this.queue = [...batch, ...this.queue]; - } - else { + } else { this.queue = [...this.queue, ...batch]; } return; @@ -291,14 +297,15 @@ class ChatRenderer { if (combinable) { combinable.times = (combinable.times || 1) + 1; updateMessageBadge(combinable); - if (( - combinable.type === MESSAGE_TYPE_COMBAT) - || combinable.type === MESSAGE_TYPE_LOCALCHAT - && combinable.times < 10) { + if ( + combinable.type === MESSAGE_TYPE_COMBAT || + (combinable.type === MESSAGE_TYPE_LOCALCHAT && combinable.times < 10) + ) { let muhstyle = combinable.node.style; - let fontsize = document.documentElement.style.getPropertyValue('font-size'); + let fontsize = + document.documentElement.style.getPropertyValue('font-size'); let basesize = parseInt(fontsize.slice(0, -2), 10); - muhstyle.setProperty('font-size', basesize + (combinable.times) + 'px'); + muhstyle.setProperty('font-size', basesize + combinable.times + 'px'); } continue; } @@ -320,15 +327,14 @@ class ChatRenderer { // Payload is HTML else if (message.html) { node.innerHTML = message.html; - } - else { + } else { logger.error('Error: message is missing text payload', message); } // Get all nodes in this message that want to be rendered like jsx - const nodes = node.querySelectorAll("[data-component]"); + const nodes = node.querySelectorAll('[data-component]'); for (let i = 0; i < nodes.length; i++) { const childNode = nodes[i]; - const targetName = childNode.getAttribute("data-component"); + const targetName = childNode.getAttribute('data-component'); // Let's pull out the attibute info we need let outputProps = {}; for (let j = 0; j < childNode.attributes.length; j++) { @@ -337,20 +343,18 @@ class ChatRenderer { let working_value = attribute.nodeValue; // We can't do the "if it has no value it's truthy" trick // Because getAttribute returns "", not null. Hate IE - if (working_value === "$true") { + if (working_value === '$true') { working_value = true; - } - else if (working_value === "$false") { + } else if (working_value === '$false') { working_value = false; - } - else if (!isNaN(working_value)) { + } else if (!isNaN(working_value)) { const parsed_float = parseFloat(working_value); if (!isNaN(parsed_float)) { working_value = parsed_float; } } - let canon_name = attribute.nodeName.replace("data-", ""); + let canon_name = attribute.nodeName.replace('data-', ''); // html attributes don't support upper case chars, so we need to map canon_name = TGUI_CHAT_ATTRIBUTES_TO_PROPS[canon_name]; outputProps[canon_name] = working_value; @@ -364,18 +368,17 @@ class ChatRenderer { render( - , childNode); + , + childNode, + ); /* eslint-enable react/no-danger */ - } // Highlight text if (!message.avoidHighlighting && this.highlightRegex) { - const highlighted = highlightNode(node, - this.highlightRegex, - text => ( - createHighlightNode(text, this.highlightColor) - )); + const highlighted = highlightNode(node, this.highlightRegex, (text) => + createHighlightNode(text, this.highlightColor), + ); if (highlighted) { node.className += ' ChatMessage--highlighted'; } @@ -400,10 +403,12 @@ class ChatRenderer { if (!message.type) { // IE8: Does not support querySelector on elements that // are not yet in the document. - const typeDef = !Byond.IS_LTE_IE8 && MESSAGE_TYPES - .find(typeDef => ( - typeDef.selector && node.querySelector(typeDef.selector) - )); + const typeDef = + !Byond.IS_LTE_IE8 && + MESSAGE_TYPES.find( + (typeDef) => + typeDef.selector && node.querySelector(typeDef.selector), + ); message.type = typeDef?.type || MESSAGE_TYPE_UNKNOWN; } updateMessageBadge(message); @@ -422,8 +427,7 @@ class ChatRenderer { const firstChild = this.rootNode.childNodes[0]; if (prepend && firstChild) { this.rootNode.insertBefore(fragment, firstChild); - } - else { + } else { this.rootNode.appendChild(fragment); } if (this.scrollTracking) { @@ -449,8 +453,7 @@ class ChatRenderer { // Visible messages { const messages = this.visibleMessages; - const fromIndex = Math.max(0, - messages.length - MAX_VISIBLE_MESSAGES); + const fromIndex = Math.max(0, messages.length - MAX_VISIBLE_MESSAGES); if (fromIndex > 0) { this.visibleMessages = messages.slice(fromIndex); for (let i = 0; i < fromIndex; i++) { @@ -460,16 +463,18 @@ class ChatRenderer { message.node = 'pruned'; } // Remove pruned messages from the message array - this.messages = this.messages.filter(message => ( - message.node !== 'pruned' - )); + this.messages = this.messages.filter( + (message) => message.node !== 'pruned', + ); logger.log(`pruned ${fromIndex} visible messages`); } } // All messages { - const fromIndex = Math.max(0, - this.messages.length - MAX_PERSISTED_MESSAGES); + const fromIndex = Math.max( + 0, + this.messages.length - MAX_PERSISTED_MESSAGES, + ); if (fromIndex > 0) { this.messages = this.messages.slice(fromIndex); logger.log(`pruned ${fromIndex} stored messages`); @@ -482,8 +487,10 @@ class ChatRenderer { return; } // Make a copy of messages - const fromIndex = Math.max(0, - this.messages.length - MAX_PERSISTED_MESSAGES); + const fromIndex = Math.max( + 0, + this.messages.length - MAX_PERSISTED_MESSAGES, + ); const messages = this.messages.slice(fromIndex); // Remove existing nodes for (let message of messages) { @@ -523,18 +530,21 @@ class ChatRenderer { } } // Create a page - const pageHtml = '\n' - + '\n' - + '\n' - + 'SS13 Chat Log\n' - + '\n' - + '\n' - + '\n' - + '
\n' - + messagesHtml - + '
\n' - + '\n' - + '\n'; + const pageHtml = + '\n' + + '\n' + + '\n' + + 'SS13 Chat Log\n' + + '\n' + + '\n' + + '\n' + + '
\n' + + messagesHtml + + '
\n' + + '\n' + + '\n'; // Create and send a nice blob const blob = new Blob([pageHtml]); const timestamp = new Date() diff --git a/tgui/packages/tgui-panel/chat/replaceInTextNode.js b/tgui/packages/tgui-panel/chat/replaceInTextNode.js index 0db2b2193e8a..53601202ec3e 100644 --- a/tgui/packages/tgui-panel/chat/replaceInTextNode.js +++ b/tgui/packages/tgui-panel/chat/replaceInTextNode.js @@ -7,7 +7,7 @@ /** * Replaces text matching a regular expression with a custom node. */ -export const replaceInTextNode = (regex, createNode) => node => { +export const replaceInTextNode = (regex, createNode) => (node) => { const text = node.textContent; const textLength = text.length; let match; @@ -15,7 +15,7 @@ export const replaceInTextNode = (regex, createNode) => node => { let fragment; let n = 0; // eslint-disable-next-line no-cond-assign - while (match = regex.exec(text)) { + while ((match = regex.exec(text))) { n += 1; // Lazy init fragment if (!fragment) { @@ -26,8 +26,9 @@ export const replaceInTextNode = (regex, createNode) => node => { const matchIndex = match.index; // Insert previous unmatched chunk if (lastIndex < matchIndex) { - fragment.appendChild(document.createTextNode( - text.substring(lastIndex, matchIndex))); + fragment.appendChild( + document.createTextNode(text.substring(lastIndex, matchIndex)), + ); } lastIndex = matchIndex + matchLength; // Create a wrapper node @@ -36,8 +37,9 @@ export const replaceInTextNode = (regex, createNode) => node => { if (fragment) { // Insert the remaining unmatched chunk if (lastIndex < textLength) { - fragment.appendChild(document.createTextNode( - text.substring(lastIndex, textLength))); + fragment.appendChild( + document.createTextNode(text.substring(lastIndex, textLength)), + ); } // Commit the fragment node.parentNode.replaceChild(fragment, node); @@ -45,17 +47,15 @@ export const replaceInTextNode = (regex, createNode) => node => { return n; }; - // Highlight // -------------------------------------------------------- /** * Default highlight node. */ -const createHighlightNode = text => { +const createHighlightNode = (text) => { const node = document.createElement('span'); - node.setAttribute('style', - 'background-color:#fd4;color:#000'); + node.setAttribute('style', 'background-color:#fd4;color:#000'); node.textContent = text; return node; }; @@ -83,19 +83,18 @@ export const highlightNode = ( // Is a text node if (node.nodeType === 3) { n += replaceInTextNode(regex, createNode)(node); - } - else { + } else { n += highlightNode(node, regex, createNode); } } return n; }; - // Linkify // -------------------------------------------------------- -const URL_REGEX = /(?:(?:https?:\/\/)|(?:www\.))(?:[^ ]*?\.[^ ]*?)+[-A-Za-z0-9+&@#/%?=~_|$!:,.;()]+/ig; +const URL_REGEX = + /(?:(?:https?:\/\/)|(?:www\.))(?:[^ ]*?\.[^ ]*?)+[-A-Za-z0-9+&@#/%?=~_|$!:,.;()]+/gi; /** * Highlights the text in the node based on the provided regular expression. @@ -103,7 +102,7 @@ const URL_REGEX = /(?:(?:https?:\/\/)|(?:www\.))(?:[^ ]*?\.[^ ]*?)+[-A-Za-z0-9+& * @param {Node} node Node which you want to process * @returns {number} Number of matches */ -export const linkifyNode = node => { +export const linkifyNode = (node) => { let n = 0; const childNodes = node.childNodes; for (let i = 0; i < childNodes.length; i++) { @@ -112,15 +111,14 @@ export const linkifyNode = node => { // Is a text node if (node.nodeType === 3) { n += linkifyTextNode(node); - } - else if (tag !== 'a') { + } else if (tag !== 'a') { n += linkifyNode(node); } } return n; }; -const linkifyTextNode = replaceInTextNode(URL_REGEX, text => { +const linkifyTextNode = replaceInTextNode(URL_REGEX, (text) => { const node = document.createElement('a'); node.href = text; node.textContent = text; diff --git a/tgui/packages/tgui-panel/chat/selectors.js b/tgui/packages/tgui-panel/chat/selectors.js index 2bcc65318409..6352b7cddf0a 100644 --- a/tgui/packages/tgui-panel/chat/selectors.js +++ b/tgui/packages/tgui-panel/chat/selectors.js @@ -6,16 +6,12 @@ import { map } from 'common/collections'; -export const selectChat = state => state.chat; +export const selectChat = (state) => state.chat; -export const selectChatPages = state => ( - map(id => state.chat.pageById[id])(state.chat.pages) -); +export const selectChatPages = (state) => + map((id) => state.chat.pageById[id])(state.chat.pages); -export const selectCurrentChatPage = state => ( - state.chat.pageById[state.chat.currentPageId] -); +export const selectCurrentChatPage = (state) => + state.chat.pageById[state.chat.currentPageId]; -export const selectChatPageById = id => state => ( - state.chat.pageById[id] -); +export const selectChatPageById = (id) => (state) => state.chat.pageById[id]; diff --git a/tgui/packages/tgui-panel/game/hooks.js b/tgui/packages/tgui-panel/game/hooks.js index e9567b916b46..859aaa09a407 100644 --- a/tgui/packages/tgui-panel/game/hooks.js +++ b/tgui/packages/tgui-panel/game/hooks.js @@ -7,6 +7,6 @@ import { useSelector } from 'common/redux'; import { selectGame } from './selectors'; -export const useGame = context => { +export const useGame = (context) => { return useSelector(context, selectGame); }; diff --git a/tgui/packages/tgui-panel/game/middleware.js b/tgui/packages/tgui-panel/game/middleware.js index ab86f80af3cf..53dd45bb46e0 100644 --- a/tgui/packages/tgui-panel/game/middleware.js +++ b/tgui/packages/tgui-panel/game/middleware.js @@ -9,7 +9,7 @@ import { connectionLost, connectionRestored, roundRestarted } from './actions'; import { selectGame } from './selectors'; import { CONNECTION_LOST_AFTER } from './constants'; -const withTimestamp = action => ({ +const withTimestamp = (action) => ({ ...action, meta: { ...action.meta, @@ -17,7 +17,7 @@ const withTimestamp = action => ({ }, }); -export const gameMiddleware = store => { +export const gameMiddleware = (store) => { let lastPingedAt; setInterval(() => { @@ -26,8 +26,8 @@ export const gameMiddleware = store => { return; } const game = selectGame(state); - const pingsAreFailing = lastPingedAt - && Date.now() >= lastPingedAt + CONNECTION_LOST_AFTER; + const pingsAreFailing = + lastPingedAt && Date.now() >= lastPingedAt + CONNECTION_LOST_AFTER; if (!game.connectionLostAt && pingsAreFailing) { store.dispatch(withTimestamp(connectionLost())); } @@ -36,7 +36,7 @@ export const gameMiddleware = store => { } }, 1000); - return next => action => { + return (next) => (action) => { const { type } = action; if (type === pingSuccess.type || type === pingSoft.type) { diff --git a/tgui/packages/tgui-panel/game/selectors.js b/tgui/packages/tgui-panel/game/selectors.js index dc2d7040f9c8..a3b93b327d97 100644 --- a/tgui/packages/tgui-panel/game/selectors.js +++ b/tgui/packages/tgui-panel/game/selectors.js @@ -4,4 +4,4 @@ * @license MIT */ -export const selectGame = state => state.game; +export const selectGame = (state) => state.game; diff --git a/tgui/packages/tgui-panel/index.js b/tgui/packages/tgui-panel/index.js index 721fa97fb50c..fed102d5fa34 100644 --- a/tgui/packages/tgui-panel/index.js +++ b/tgui/packages/tgui-panel/index.js @@ -81,32 +81,35 @@ const setupApp = () => { Byond.winset('browseroutput', { 'is-visible': true, 'is-disabled': false, - 'pos': '0x0', - 'size': '0x0', + pos: '0x0', + size: '0x0', }); // Resize the panel to match the non-browser output - Byond.winget('output').then(output => { + Byond.winget('output').then((output) => { Byond.winset('browseroutput', { - 'size': output.size, + size: output.size, }); }); // Enable hot module reloading if (module.hot) { setupHotReloading(); - module.hot.accept([ - './audio', - './chat', - './game', - './Notifications', - './Panel', - './ping', - './settings', - './telemetry', - ], () => { - renderApp(); - }); + module.hot.accept( + [ + './audio', + './chat', + './game', + './Notifications', + './Panel', + './ping', + './settings', + './telemetry', + ], + () => { + renderApp(); + }, + ); } }; diff --git a/tgui/packages/tgui-panel/panelFocus.js b/tgui/packages/tgui-panel/panelFocus.js index 6922418c8997..b7cea2293149 100644 --- a/tgui/packages/tgui-panel/panelFocus.js +++ b/tgui/packages/tgui-panel/panelFocus.js @@ -20,13 +20,13 @@ const deferredFocusMap = () => setImmediate(() => focusMap()); export const setupPanelFocusHacks = () => { let focusStolen = false; let clickStartPos = null; - window.addEventListener('focusin', e => { + window.addEventListener('focusin', (e) => { focusStolen = canStealFocus(e.target); }); - window.addEventListener('mousedown', e => { + window.addEventListener('mousedown', (e) => { clickStartPos = [e.screenX, e.screenY]; }); - window.addEventListener('mouseup', e => { + window.addEventListener('mouseup', (e) => { if (clickStartPos) { const clickEndPos = [e.screenX, e.screenY]; const dist = vecLength(vecSubtract(clickEndPos, clickStartPos)); @@ -38,7 +38,7 @@ export const setupPanelFocusHacks = () => { deferredFocusMap(); } }); - globalEvents.on('keydown', key => { + globalEvents.on('keydown', (key) => { if (key.isModifierKey()) { return; } diff --git a/tgui/packages/tgui-panel/ping/PingIndicator.js b/tgui/packages/tgui-panel/ping/PingIndicator.js index b663cd3a1809..aadbd1c134b5 100644 --- a/tgui/packages/tgui-panel/ping/PingIndicator.js +++ b/tgui/packages/tgui-panel/ping/PingIndicator.js @@ -17,14 +17,10 @@ export const PingIndicator = (props, context) => { new Color(220, 200, 40), new Color(60, 220, 40), ]); - const roundtrip = ping.roundtrip - ? toFixed(ping.roundtrip) - : '--'; + const roundtrip = ping.roundtrip ? toFixed(ping.roundtrip) : '--'; return (
- + {roundtrip}
); diff --git a/tgui/packages/tgui-panel/ping/middleware.js b/tgui/packages/tgui-panel/ping/middleware.js index fb86de9cc48f..e5b593d822fd 100644 --- a/tgui/packages/tgui-panel/ping/middleware.js +++ b/tgui/packages/tgui-panel/ping/middleware.js @@ -7,7 +7,7 @@ import { pingFail, pingReply, pingSoft, pingSuccess } from './actions'; import { PING_QUEUE_SIZE, PING_TIMEOUT } from './constants'; -export const pingMiddleware = store => { +export const pingMiddleware = (store) => { let initialized = false; let index = 0; const pings = []; @@ -26,7 +26,7 @@ export const pingMiddleware = store => { index = (index + 1) % PING_QUEUE_SIZE; }; - return next => action => { + return (next) => (action) => { const { type, payload } = action; if (!initialized) { diff --git a/tgui/packages/tgui-panel/ping/reducer.js b/tgui/packages/tgui-panel/ping/reducer.js index 874cb75a9b8d..49b9522c06fc 100644 --- a/tgui/packages/tgui-panel/ping/reducer.js +++ b/tgui/packages/tgui-panel/ping/reducer.js @@ -6,7 +6,11 @@ import { clamp01, scale } from 'common/math'; import { pingFail, pingSuccess } from './actions'; -import { PING_MAX_FAILS, PING_ROUNDTRIP_BEST, PING_ROUNDTRIP_WORST } from './constants'; +import { + PING_MAX_FAILS, + PING_ROUNDTRIP_BEST, + PING_ROUNDTRIP_WORST, +} from './constants'; export const pingReducer = (state = {}, action) => { const { type, payload } = action; @@ -15,8 +19,8 @@ export const pingReducer = (state = {}, action) => { const { roundtrip } = payload; const prevRoundtrip = state.roundtripAvg || roundtrip; const roundtripAvg = Math.round(prevRoundtrip * 0.4 + roundtrip * 0.6); - const networkQuality = 1 - scale(roundtripAvg, - PING_ROUNDTRIP_BEST, PING_ROUNDTRIP_WORST); + const networkQuality = + 1 - scale(roundtripAvg, PING_ROUNDTRIP_BEST, PING_ROUNDTRIP_WORST); return { roundtrip, roundtripAvg, @@ -27,8 +31,9 @@ export const pingReducer = (state = {}, action) => { if (type === pingFail.type) { const { failCount = 0 } = state; - const networkQuality = clamp01(state.networkQuality - - failCount / PING_MAX_FAILS); + const networkQuality = clamp01( + state.networkQuality - failCount / PING_MAX_FAILS, + ); const nextState = { ...state, failCount: failCount + 1, diff --git a/tgui/packages/tgui-panel/ping/selectors.js b/tgui/packages/tgui-panel/ping/selectors.js index cfbe95c2f325..1b8bfb4ee40f 100644 --- a/tgui/packages/tgui-panel/ping/selectors.js +++ b/tgui/packages/tgui-panel/ping/selectors.js @@ -4,4 +4,4 @@ * @license MIT */ -export const selectPing = state => state.ping; +export const selectPing = (state) => state.ping; diff --git a/tgui/packages/tgui-panel/reconnect.tsx b/tgui/packages/tgui-panel/reconnect.tsx index 25391c0a681f..b3ee9777731e 100644 --- a/tgui/packages/tgui-panel/reconnect.tsx +++ b/tgui/packages/tgui-panel/reconnect.tsx @@ -3,7 +3,7 @@ import { Button } from 'tgui/components'; let url: string | null = null; setInterval(() => { - Byond.winget('', 'url').then(currentUrl => { + Byond.winget('', 'url').then((currentUrl) => { // Sometimes, for whatever reason, BYOND will give an IP with a :0 port. if (currentUrl && !currentUrl.match(/:0$/)) { url = currentUrl; @@ -12,20 +12,28 @@ setInterval(() => { }, 5000); export const ReconnectButton = (props, context) => { - return url && ( - <> - + return ( + url && ( + <> + - - + + + ) ); }; diff --git a/tgui/packages/tgui-panel/settings/SettingsPanel.js b/tgui/packages/tgui-panel/settings/SettingsPanel.js index eb2cac65e34a..b746a6c4f613 100644 --- a/tgui/packages/tgui-panel/settings/SettingsPanel.js +++ b/tgui/packages/tgui-panel/settings/SettingsPanel.js @@ -7,7 +7,21 @@ import { toFixed } from 'common/math'; import { useLocalState } from 'tgui/backend'; import { useDispatch, useSelector } from 'common/redux'; -import { Box, Button, ColorBox, Divider, Dropdown, Flex, Input, LabeledList, NumberInput, Section, Stack, Tabs, TextArea } from 'tgui/components'; +import { + Box, + Button, + ColorBox, + Divider, + Dropdown, + Flex, + Input, + LabeledList, + NumberInput, + Section, + Stack, + Tabs, + TextArea, +} from 'tgui/components'; import { ChatPageSettings } from '../chat'; import { rebuildChat, saveChatToDisk } from '../chat/actions'; import { changeSettingsTab, updateSettings } from './actions'; @@ -22,13 +36,18 @@ export const SettingsPanel = (props, context) => {
- {SETTINGS_TABS.map(tab => ( + {SETTINGS_TABS.map((tab) => ( dispatch(changeSettingsTab({ - tabId: tab.id, - }))}> + onClick={() => + dispatch( + changeSettingsTab({ + tabId: tab.id, + }), + ) + } + > {tab.name} ))} @@ -36,12 +55,8 @@ export const SettingsPanel = (props, context) => {
- {activeTab === 'general' && ( - - )} - {activeTab === 'chatPage' && ( - - )} + {activeTab === 'general' && } + {activeTab === 'chatPage' && } ); @@ -59,7 +74,7 @@ export const SettingsGeneral = (props, context) => { matchCase, } = useSelector(context, selectSettings); const dispatch = useDispatch(context); - const [freeFont, setFreeFont] = useLocalState(context, "freeFont", false); + const [freeFont, setFreeFont] = useLocalState(context, 'freeFont', false); return (
@@ -67,34 +82,48 @@ export const SettingsGeneral = (props, context) => { dispatch(updateSettings({ - theme: value, - }))} /> + onSelected={(value) => + dispatch( + updateSettings({ + theme: value, + }), + ) + } + /> - {!freeFont && ( + {(!freeFont && ( dispatch(updateSettings({ - fontFamily: value, - }))} /> - ) || ( + onSelected={(value) => + dispatch( + updateSettings({ + fontFamily: value, + }), + ) + } + /> + )) || ( dispatch(updateSettings({ - fontFamily: value, - }))} + onChange={(e, value) => + dispatch( + updateSettings({ + fontFamily: value, + }), + ) + } /> )}
@@ -134,9 +149,12 @@ const NewscasterChannelCreation = (props, context) => { @@ -122,25 +146,28 @@ const OutfitSlot = (props, context) => { title={currItem?.desc} style={{ '-ms-interpolation-mode': 'nearest-neighbor', - }} /> + }} + /> act("clear", { slot })} /> + onClick={() => act('clear', { slot })} + /> )} - {currItem?.name || "Empty"} + title={currItem?.path} + > + {currItem?.name || 'Empty'} ); diff --git a/tgui/packages/tgui/interfaces/OutfitManager.js b/tgui/packages/tgui/interfaces/OutfitManager.js index ed7b835897f1..d3a402b04c13 100644 --- a/tgui/packages/tgui/interfaces/OutfitManager.js +++ b/tgui/packages/tgui/interfaces/OutfitManager.js @@ -6,11 +6,7 @@ export const OutfitManager = (props, context) => { const { act, data } = useBackend(context); const { outfits } = data; return ( - +
{ icon="file-upload" tooltip="Load an outfit from a file" tooltipPosition="left" - onClick={() => act("load")} /> + onClick={() => act('load')} + /> )} } fill scrollable - title="pAI Candidates"> + title="pAI Candidates" + > {!candidates.length ? ( None found! ) : ( @@ -102,24 +112,27 @@ const CandidateDisplay = (props, context) => { return ( + padding: '1rem', + }} + >
act('download', { key })} - tooltip="Accepts this pAI candidate."> + tooltip="Accepts this pAI candidate." + > Download } fill height={12} scrollable - title={'Candidate ' + index}> + title={'Candidate ' + index} + > Name: {name || 'Randomized Name'} @@ -153,7 +166,8 @@ const PaiOptions = (_, context) => { @@ -161,7 +175,8 @@ const PaiOptions = (_, context) => { @@ -169,7 +184,8 @@ const PaiOptions = (_, context) => { diff --git a/tgui/packages/tgui/interfaces/PaiInterface.tsx b/tgui/packages/tgui/interfaces/PaiInterface.tsx index 19641ab81d6c..1664956bfc25 100644 --- a/tgui/packages/tgui/interfaces/PaiInterface.tsx +++ b/tgui/packages/tgui/interfaces/PaiInterface.tsx @@ -1,5 +1,17 @@ import { useBackend, useLocalState } from '../backend'; -import { Box, Button, LabeledList, Icon, NoticeBox, ProgressBar, Section, Stack, Table, Tabs, Tooltip } from '../components'; +import { + Box, + Button, + LabeledList, + Icon, + NoticeBox, + ProgressBar, + Section, + Stack, + Table, + Tabs, + Tooltip, +} from '../components'; import { Window } from '../layouts'; type PaiInterfaceData = { @@ -82,8 +94,7 @@ const SOFTWARE_DESC = { 'security HUD': 'Allows you to view security records using an overlay HUD.', 'loudness booster': 'Synthesizes instruments, plays sounds and imported songs.', - 'newscaster': - 'A tool that allows you to broadcast news to other crew members.', + newscaster: 'A tool that allows you to broadcast news to other crew members.', 'door jack': 'A tool that allows you to open doors.', 'encryption keys': 'A tool that allows you to decrypt and speak on other radio frequencies.', @@ -92,15 +103,15 @@ const SOFTWARE_DESC = { }; const ICON_MAP = { - 'angry': 'angry', - 'cat': 'cat', + angry: 'angry', + cat: 'cat', 'extremely-happy': 'grin-beam', - 'laugh': 'grin-squint', - 'happy': 'smile', - 'off': 'power-off', - 'sad': 'frown', - 'sunglasses': 'sun', - 'what': 'question', + laugh: 'grin-squint', + happy: 'smile', + off: 'power-off', + sad: 'frown', + sunglasses: 'sun', + what: 'question', }; export const PaiInterface = (_, context) => { @@ -137,25 +148,29 @@ const TabDisplay = (props) => { onTabClick(Tab.System)} - selected={tab === Tab.System}> + selected={tab === Tab.System} + > System onTabClick(Tab.Directive)} - selected={tab === Tab.Directive}> + selected={tab === Tab.Directive} + > Directives onTabClick(Tab.Installed)} - selected={tab === Tab.Installed}> + selected={tab === Tab.Installed} + > Installed onTabClick(Tab.Available)} - selected={tab === Tab.Available}> + selected={tab === Tab.Available} + > Download @@ -233,20 +248,23 @@ const SystemInfo = (_, context) => { disabled={!master.dna} icon="dna" onClick={() => act('check_dna')} - tooltip="Verifies your master's DNA. Must be carried in hand."> + tooltip="Verifies your master's DNA. Must be carried in hand." + > Verify } fill scrollable - title="System Info"> + title="System Info" + > {master.name || 'None.'} @@ -302,7 +320,7 @@ const InstalledDisplay = (_, context) => { const [installSelected, setInstallSelected] = useLocalState( context, 'software', - '' + '', ); const onInstallHandler = (software: string) => { setInstallSelected(software); @@ -335,7 +353,7 @@ const InstalledSoftware = (props, context) => { return ( ); @@ -363,8 +381,10 @@ const InstalledInfo = (props) => { !software ? 'Select a Program' : software.replace(/(^\w{1})|(\s+\w{1})/g, (letter) => - letter.toUpperCase()) - }> + letter.toUpperCase(), + ) + } + > {software && ( {SOFTWARE_DESC[software] || ''} @@ -394,7 +414,8 @@ const RecordsDisplay = (props, context) => { @@ -404,7 +425,8 @@ const RecordsDisplay = (props, context) => { } fill - scrollable> + scrollable + > {convertedRecords?.map((record) => { return ; @@ -462,19 +484,22 @@ const SoftwareButtons = (props, context) => { @@ -485,20 +510,23 @@ const SoftwareButtons = (props, context) => { @@ -508,17 +536,20 @@ const SoftwareButtons = (props, context) => { <> @@ -529,7 +560,8 @@ const SoftwareButtons = (props, context) => { ); @@ -538,7 +570,8 @@ const SoftwareButtons = (props, context) => { ); @@ -551,7 +584,8 @@ const AvailableDisplay = () => { buttons={} fill scrollable - title="Available Software"> + title="Available Software" + > ); @@ -634,7 +668,8 @@ const AvailableRow = (props, context) => { mb={0.5} disabled={ram < software.value || purchased} onClick={() => act('buy', { selection: software.name })} - tooltip={SOFTWARE_DESC[software.name] || ''}> + tooltip={SOFTWARE_DESC[software.name] || ''} + > diff --git a/tgui/packages/tgui/interfaces/PaiSubmit.tsx b/tgui/packages/tgui/interfaces/PaiSubmit.tsx index 01762b52f653..833a2c4b7641 100644 --- a/tgui/packages/tgui/interfaces/PaiSubmit.tsx +++ b/tgui/packages/tgui/interfaces/PaiSubmit.tsx @@ -123,14 +123,16 @@ const ButtonsDisplay = (props, context) => { @@ -139,7 +141,9 @@ const ButtonsDisplay = (props, context) => { onClick={() => act('submit', { candidate: input, - })}> + }) + } + > SUBMIT diff --git a/tgui/packages/tgui/interfaces/PaintingAdminPanel.tsx b/tgui/packages/tgui/interfaces/PaintingAdminPanel.tsx index d2d6e42ef3de..25d3b99d0ac9 100644 --- a/tgui/packages/tgui/interfaces/PaintingAdminPanel.tsx +++ b/tgui/packages/tgui/interfaces/PaintingAdminPanel.tsx @@ -9,37 +9,39 @@ type PaintingAdminPanelData = { }; type PaintingData = { - md5: string, - title: string, - creator_ckey: string, - creator_name: string | null, - creation_date: Date | null, - creation_round_id: number | null, - patron_ckey: string | null, - patron_name: string | null, - credit_value: number, - width: number, - height: number, - ref: string, - tags: string[] | null, - medium: string | null -} + md5: string; + title: string; + creator_ckey: string; + creator_name: string | null; + creation_date: Date | null; + creation_round_id: number | null; + patron_ckey: string | null; + patron_name: string | null; + credit_value: number; + width: number; + height: number; + ref: string; + tags: string[] | null; + medium: string | null; +}; export const PaintingAdminPanel = (props, context) => { const { act, data } = useBackend(context); - const [chosenPaintingRef, setChosenPaintingRef] = useLocalState(context, 'chosenPainting', null); - const { - paintings, - } = data; - const chosenPainting = paintings.find(p => p.ref === chosenPaintingRef); + const [chosenPaintingRef, setChosenPaintingRef] = useLocalState< + string | null + >(context, 'chosenPainting', null); + const { paintings } = data; + const chosenPainting = paintings.find((p) => p.ref === chosenPaintingRef); return ( - + {chosenPainting && ( -
setChosenPaintingRef(null)}>Close}> +
setChosenPaintingRef(null)}>Close + } + > { style={{ 'vertical-align': 'middle', '-ms-interpolation-mode': 'nearest-neighbor', - }} /> + }} + /> - {decodeHtmlEntities(chosenPainting.title)} - + { + setChosenPaintingRef(null); + act('delete', { ref: chosenPainting.ref }); + }} + > + Delete + +
)} @@ -96,23 +149,22 @@ export const PaintingAdminPanel = (props, context) => { Preview Actions - {paintings.map(painting => ( - - + {paintings.map((painting) => ( + + {decodeHtmlEntities(painting.title)} {painting.creator_ckey} - + + - ); - })} + return ( + + ); + })} ); @@ -271,18 +286,19 @@ const SpecimenDisplay = (_, context) => { onClick={() => act('create_culture_bottle', { index: virus.index, - })} + }) + } /> - }> + } + > - {virus?.symptoms - && } + {virus?.symptoms && } @@ -304,7 +320,8 @@ const VirusTabs = (props: TabsProps, context) => { tabHandler(index)} - key={virus.name}> + key={virus.name} + > {virus.name} ); @@ -352,7 +369,8 @@ const VirusTextInfo = (props: VirusInfoProps, context) => { act('rename_disease', { index: virus.index, name: value, - })} + }) + } /> ) : ( {virus.name} @@ -383,14 +401,16 @@ const VirusTraitInfo = (props: VirusInfoProps) => { + label="Resistance" + > {virus.resistance} + label="Stage speed" + > {virus.stage_speed} @@ -402,7 +422,8 @@ const VirusTraitInfo = (props: VirusInfoProps) => { + label="Transmissibility" + > {virus.transmission} @@ -457,14 +478,16 @@ const SymptomTraitInfo = (props: SymptomInfoProps) => { + label="Resistance" + > {symptom.resistance} + label="Stage Speed" + > {symptom.stage_speed} @@ -476,7 +499,8 @@ const SymptomTraitInfo = (props: SymptomInfoProps) => { + label="Transmission" + > {symptom.transmission} diff --git a/tgui/packages/tgui/interfaces/PaperSheet.js b/tgui/packages/tgui/interfaces/PaperSheet.js index 809d6c3a9683..17f031564b9c 100644 --- a/tgui/packages/tgui/interfaces/PaperSheet.js +++ b/tgui/packages/tgui/interfaces/PaperSheet.js @@ -22,58 +22,86 @@ const MAX_PAPER_LENGTH = 5000; // Question, should we send this with ui_data? // Hacky, yes, works?...yes const textWidth = (text, font, fontsize) => { // default font height is 12 in tgui - font = fontsize + "x " + font; + font = fontsize + 'x ' + font; const c = document.createElement('canvas'); - const ctx = c.getContext("2d"); + const ctx = c.getContext('2d'); ctx.font = font; const width = ctx.measureText(text).width; return width; }; -const setFontinText = (text, font, color, bold=false, italics=false) => { - return "" + text + ""; +const setFontinText = (text, font, color, bold = false, italics = false) => { + return ( + '' + + text + + '' + ); }; -const createIDHeader = index => { - return "paperfield_" + index; +const createIDHeader = (index) => { + return 'paperfield_' + index; }; // To make a field you do a [_______] or however long the field is // we will then output a TEXT input for it that hopefully covers // the exact amount of spaces const field_regex = /\[(_+)\]/g; -const field_tag_regex = /\[paperfield_\d+)"(.*?)\/>\]/gm; -const sign_regex = /%s(?:ign)?(?=\\s|$)?/igm; - -const createInputField = (length, width, font, - fontsize, color, id) => { - return "[]"; +const field_tag_regex = + /\[paperfield_\d+)"(.*?)\/>\]/gm; +const sign_regex = /%s(?:ign)?(?=\\s|$)?/gim; + +const createInputField = (length, width, font, fontsize, color, id) => { + return ( + '[]' + ); }; const createFields = (txt, font, fontsize, color, counter) => { const ret_text = txt.replace(field_regex, (match, p1, offset, string) => { - const width = textWidth(match, font, fontsize) + "px"; - return createInputField(p1.length, - width, font, fontsize, color, createIDHeader(counter++)); + const width = textWidth(match, font, fontsize) + 'px'; + return createInputField( + p1.length, + width, + font, + fontsize, + color, + createIDHeader(counter++), + ); }); return { counter, @@ -83,14 +111,14 @@ const createFields = (txt, font, fontsize, color, counter) => { const signDocument = (txt, color, user) => { return txt.replace(sign_regex, () => { - return setFontinText(user, "Times New Roman", color, true, true); + return setFontinText(user, 'Times New Roman', color, true, true); }); }; -const run_marked_default = value => { +const run_marked_default = (value) => { // Override function, any links and images should // kill any other marked tokens we don't want here - const walkTokens = token => { + const walkTokens = (token) => { switch (token.type) { case 'url': case 'autolink': @@ -100,7 +128,7 @@ const run_marked_default = value => { token.type = 'text'; // Once asset system is up change to some default image // or rewrite for icon images - token.href = ""; + token.href = ''; break; } }; @@ -115,17 +143,17 @@ const run_marked_default = value => { }; /* -** This gets the field, and finds the dom object and sees if -** the user has typed something in. If so, it replaces, -** the dom object, in txt with the value, spaces so it -** fits the [] format and saves the value into a object -** There may be ways to optimize this in javascript but -** doing this in byond is nightmarish. -** -** It returns any values that were saved and a corrected -** html code or null if nothing was updated -*/ -const checkAllFields = (txt, font, color, user_name, bold=false) => { + ** This gets the field, and finds the dom object and sees if + ** the user has typed something in. If so, it replaces, + ** the dom object, in txt with the value, spaces so it + ** fits the [] format and saves the value into a object + ** There may be ways to optimize this in javascript but + ** doing this in byond is nightmarish. + ** + ** It returns any values that were saved and a corrected + ** html code or null if nothing was updated + */ +const checkAllFields = (txt, font, color, user_name, bold = false) => { let matches; let values = {}; let replace = []; @@ -140,7 +168,7 @@ const checkAllFields = (txt, font, color, user_name, bold=false) => { const dom = document.getElementById(id); // make sure we got data, and kill any html that might // be in it - const dom_text = dom && dom.value ? dom.value : ""; + const dom_text = dom && dom.value ? dom.value : ''; if (dom_text.length === 0) { continue; } @@ -152,65 +180,61 @@ const checkAllFields = (txt, font, color, user_name, bold=false) => { const target = dom.cloneNode(true); // in case they sign in a field if (sanitized_text.match(sign_regex)) { - target.style.fontFamily = "Times New Roman"; + target.style.fontFamily = 'Times New Roman'; bold = true; target.defaultValue = user_name; - } - else { + } else { target.style.fontFamily = font; target.defaultValue = sanitized_text; } if (bold) { - target.style.fontWeight = "bold"; + target.style.fontWeight = 'bold'; } target.style.color = color; target.disabled = true; const wrap = document.createElement('div'); wrap.appendChild(target); values[id] = sanitized_text; // save the data - replace.push({ value: "[" + wrap.innerHTML + "]", raw_text: full_match }); + replace.push({ value: '[' + wrap.innerHTML + ']', raw_text: full_match }); } } if (replace.length > 0) { for (const o of replace) { - txt = txt.replace(o.raw_text, o.value); } } return { text: txt, fields: values }; }; -const pauseEvent = e => { - if (e.stopPropagation) { e.stopPropagation(); } - if (e.preventDefault) { e.preventDefault(); } - e.cancelBubble=true; - e.returnValue=false; +const pauseEvent = (e) => { + if (e.stopPropagation) { + e.stopPropagation(); + } + if (e.preventDefault) { + e.preventDefault(); + } + e.cancelBubble = true; + e.returnValue = false; return false; }; const Stamp = (props, context) => { - const { - image, - opacity, - } = props; + const { image, opacity } = props; const stamp_transform = { - 'left': image.x + 'px', - 'top': image.y + 'px', - 'transform': 'rotate(' + image.rotate + 'deg)', - 'opacity': opacity || 1.0, + left: image.x + 'px', + top: image.y + 'px', + transform: 'rotate(' + image.rotate + 'deg)', + opacity: opacity || 1.0, }; return (
+ className={classes(['Paper__Stamp', image.sprite])} + style={stamp_transform} + /> ); }; - const setInputReadonly = (text, readonly) => { return readonly ? text.replace(/ { // got to make this a full component if we // want to control updates const PaperSheetView = (props, context) => { - const { - value = "", - stamps = [], - backgroundColor, - readOnly, - } = props; + const { value = '', stamps = [], backgroundColor, readOnly } = props; const stamp_list = stamps; const text_html = { - __html: '' - + setInputReadonly(value, readOnly) - + '', + __html: + '' + + setInputReadonly(value, readOnly) + + '', }; return ( + height="100%" + > + p="10px" + /> {stamp_list.map((o, i) => ( - + ))} ); @@ -263,22 +287,28 @@ class PaperSheetStamper extends Component { rotate: 0, }; this.style = null; - this.handleMouseMove = e => { + this.handleMouseMove = (e) => { const pos = this.findStampPosition(e); - if (!pos) { return; } + if (!pos) { + return; + } // center offset of stamp & rotate pauseEvent(e); this.setState({ x: pos[0], y: pos[1], rotate: pos[2] }); }; - this.handleMouseClick = e => { - if (e.pageY <= 30) { return; } + this.handleMouseClick = (e) => { + if (e.pageY <= 30) { + return; + } const { act, data } = useBackend(this.context); const stamp_obj = { - x: this.state.x, y: this.state.y, r: this.state.rotate, + x: this.state.x, + y: this.state.y, + r: this.state.rotate, stamp_class: this.props.stamp_class, stamp_icon_state: data.stamp_icon_state, }; - act("stamp", stamp_obj); + act('stamp', stamp_obj); }; } @@ -289,30 +319,30 @@ class PaperSheetStamper extends Component { rotating = true; } - if (document.getElementById("stamp")) - { - const stamp = document.getElementById("stamp"); + if (document.getElementById('stamp')) { + const stamp = document.getElementById('stamp'); const stampHeight = stamp.clientHeight; const stampWidth = stamp.clientWidth; - const currentHeight = rotating ? this.state.y : e.pageY - - windowRef.scrollTop - stampHeight; - const currentWidth = rotating ? this.state.x : e.pageX - (stampWidth / 2); + const currentHeight = rotating + ? this.state.y + : e.pageY - windowRef.scrollTop - stampHeight; + const currentWidth = rotating ? this.state.x : e.pageX - stampWidth / 2; const widthMin = 0; const heightMin = 0; - const widthMax = (windowRef.clientWidth) - ( - stampWidth); - const heightMax = (windowRef.clientHeight - windowRef.scrollTop) - ( - stampHeight); + const widthMax = windowRef.clientWidth - stampWidth; + const heightMax = + windowRef.clientHeight - windowRef.scrollTop - stampHeight; const radians = Math.atan2( e.pageX - currentWidth, - e.pageY - currentHeight + e.pageY - currentHeight, ); - const rotate = rotating ? (radians * (180 / Math.PI) * -1) + const rotate = rotating + ? radians * (180 / Math.PI) * -1 : this.state.rotate; const pos = [ @@ -325,21 +355,17 @@ class PaperSheetStamper extends Component { } componentDidMount() { - document.addEventListener("mousemove", this.handleMouseMove); - document.addEventListener("click", this.handleMouseClick); + document.addEventListener('mousemove', this.handleMouseMove); + document.addEventListener('click', this.handleMouseClick); } componentWillUnmount() { - document.removeEventListener("mousemove", this.handleMouseMove); - document.removeEventListener("click", this.handleMouseClick); + document.removeEventListener('mousemove', this.handleMouseMove); + document.removeEventListener('click', this.handleMouseClick); } render() { - const { - value, - stamp_class, - stamps, - } = this.props; + const { value, stamp_class, stamps } = this.props; const stamp_list = stamps || []; const current_pos = { sprite: stamp_class, @@ -349,13 +375,8 @@ class PaperSheetStamper extends Component { }; return ( <> - - + + ); } @@ -379,19 +400,29 @@ const createPreview = ( value = value.trim(); if (value.length > 0) { // First lets make sure it ends in a new line - value += value[value.length] === "\n" ? " \n" : "\n \n"; + value += value[value.length] === '\n' ? ' \n' : '\n \n'; // Second, we sanitize the text of html const sanitized_text = sanitizeText(value); const signed_text = signDocument(sanitized_text, color, user_name); // Third we replace the [__] with fields as markedjs fucks them up const fielded_text = createFields( - signed_text, font, 12, color, field_counter); + signed_text, + font, + 12, + color, + field_counter, + ); // Fourth, parse the text using markup const formatted_text = run_marked_default(fielded_text.text); // Fifth, we wrap the created text in the pin color, and font. // crayon is bold ( tags), maybe make fountain pin italic? const fonted_text = setFontinText( - formatted_text, font, color, is_crayon, false); + formatted_text, + font, + color, + is_crayon, + false, + ); out.text += fonted_text; out.field_counter = fielded_text.counter; } @@ -400,7 +431,12 @@ const createPreview = ( // if any data was entered by the user and // if it was return the data and modify the text const final_processing = checkAllFields( - out.text, font, color, user_name, is_crayon); + out.text, + font, + color, + user_name, + is_crayon, + ); out.text = final_processing.text; out.form_fields = final_processing.fields; } @@ -414,18 +450,19 @@ class PaperSheetEdit extends Component { constructor(props, context) { super(props, context); this.state = { - previewSelected: "Preview", - old_text: props.value || "", + previewSelected: 'Preview', + old_text: props.value || '', counter: props.counter || 0, - textarea_text: "", - combined_text: props.value || "", + textarea_text: '', + combined_text: props.value || '', showingHelpTip: false, }; } createPreviewFromData(value, do_fields = false) { const { data } = useBackend(this.context); - return createPreview(value, + return createPreview( + value, this.state.old_text, do_fields, this.state.counter, @@ -437,15 +474,17 @@ class PaperSheetEdit extends Component { } onInputHandler(e, value) { if (value !== this.state.textarea_text) { - const combined_length = this.state.old_text.length - + this.state.textarea_text.length; + const combined_length = + this.state.old_text.length + this.state.textarea_text.length; if (combined_length > MAX_PAPER_LENGTH) { - if ((combined_length - MAX_PAPER_LENGTH) >= value.length) { + if (combined_length - MAX_PAPER_LENGTH >= value.length) { // Basically we cannot add any more text to the paper value = ''; } else { - value = value.substr(0, value.length - - (combined_length - MAX_PAPER_LENGTH)); + value = value.substr( + 0, + value.length - (combined_length - MAX_PAPER_LENGTH), + ); } // we check again to save an update if (value === this.state.textarea_text) { @@ -464,88 +503,91 @@ class PaperSheetEdit extends Component { const { act } = useBackend(this.context); const final_processing = this.createPreviewFromData(new_text, true); act('save', final_processing); - this.setState(() => { return { - textarea_text: "", - previewSelected: "save", - combined_text: final_processing.text, - old_text: final_processing.text, - counter: final_processing.field_counter, - }; }); + this.setState(() => { + return { + textarea_text: '', + previewSelected: 'save', + combined_text: final_processing.text, + old_text: final_processing.text, + counter: final_processing.field_counter, + }; + }); // byond should switch us to readonly mode from here } render() { - const { - textColor, - fontFamily, - stamps, - backgroundColor, - } = this.props; + const { textColor, fontFamily, stamps, backgroundColor } = this.props; return ( - + - + this.setState({ previewSelected: "Edit" })}> + backgroundColor={ + this.state.previewSelected === 'Edit' ? 'grey' : 'white' + } + selected={this.state.previewSelected === 'Edit'} + onClick={() => this.setState({ previewSelected: 'Edit' })} + > Edit this.setState(() => { - const new_state = { - previewSelected: "Preview", - textarea_text: this.state.textarea_text, - combined_text: this.createPreviewFromData( - this.state.textarea_text).text, - }; - return new_state; - })}> + backgroundColor={ + this.state.previewSelected === 'Preview' ? 'grey' : 'white' + } + selected={this.state.previewSelected === 'Preview'} + onClick={() => + this.setState(() => { + const new_state = { + previewSelected: 'Preview', + textarea_text: this.state.textarea_text, + combined_text: this.createPreviewFromData( + this.state.textarea_text, + ).text, + }; + return new_state; + }) + } + > Preview { - if (this.state.previewSelected === "confirm") { + if (this.state.previewSelected === 'confirm') { this.finalUpdate(this.state.textarea_text); - } - else if (this.state.previewSelected === "Edit") { + } else if (this.state.previewSelected === 'Edit') { this.setState(() => { const new_state = { - previewSelected: "confirm", + previewSelected: 'confirm', textarea_text: this.state.textarea_text, combined_text: this.createPreviewFromData( - this.state.textarea_text).text, + this.state.textarea_text, + ).text, }; return new_state; }); + } else { + this.setState({ previewSelected: 'confirm' }); } - else { - this.setState({ previewSelected: "confirm" }); - } - }}> - {this.state.previewSelected === "confirm" ? "Confirm" : "Save"} + }} + > + {this.state.previewSelected === 'confirm' ? 'Confirm' : 'Save'} { this.setState({ showingHelpTip: false }); - }}> + }} + > Help - - {this.state.previewSelected === "Edit" && ( + + {(this.state.previewSelected === 'Edit' && (