A few uses of `array.sort()` have been left alone:
- sorting in `data/` because they aren't supposed to import anything
- `set-importer` because I still have no clue what that's for and what
dependencies it is/isn't allowed to have
- `sort()` with no arguments used as a lexical sort (at which point
`sortBy` offers no benefits)
All other cases have been replaced with `Utils.sortBy`, which should
be a massive increase in readability.
Sort orders should be much more readable now, without needing to puzzle
through sign issues. The order is always low-to-high, A-to-Z,
true-to-false.
This is the change that renames:
- `Dex.getMove` -> `Dex.moves.get`
- `Dex.getAbility` -> `Dex.abilities.get`
- `Dex.getItem` -> `Dex.items.get`
- `Dex.getSpecies` -> `Dex.species.get`
- `Dex.getEffect` -> `Dex.conditions.get`
- `Dex.getNature` -> `Dex.natures.get`
- `Dex.getType` -> `Dex.types.get`
- `Dex.getFormat` -> `Dex.formats.get`
In addition, some other APIs have been updated:
- `getByID` methods have also been added to every other table.
- `Dex.moves.all()` now gets an array of all moves
- Plus equivalent methods for `abilities`, `items`, `species`, `formats`, `natures`, `types`
- Note: there's no `Dex.conditions.all()`
- new API: `Dex.stats` for naming/iterating stats
- `Dex.getEffectByID` -> `Dex.conditions.getByID`
- `Dex.getType` -> `Dex.types.get`
- `Dex.data.Formats` -> `Dex.data.Rulesets`
- `Dex.formats` -> now an array `Dex.formats.all()`
- `Dex.getRuleTable` -> `Dex.formats.getRuleTable`
- `Dex.validateFormat` -> `Dex.formats.validate`
Team functions have been split off into a new `sim/teams` package:
- `Dex.packTeam` -> `Teams.pack`
- `Dex.fastUnpackTeam` -> `Teams.unpack`
- `Dex.generateTeam` -> `Teams.generate`
- `Dex.stringifyTeam` -> `Teams.export`
`Teams.export` has also been rewritten to better match how it works in client.
This implements #8178
Better subprocess query system for #7937.
I mentioned in #7937 that it should be a regular `child_process`, but
Mia's not _wrong_ that PM has some useful features that make it more
convenient than `child_process`. This change allows a
`QueryProcessManager` to easily run a query in a new child process.
This removes the need for some more casting... although I'm starting
to worry if generics are too unreadable. I suppose anyone working on
library code is likely to prefer generics to casting, and it's safer,
anyway.
- `writeUpdate` state is now stored in a global variable, so hotpatching doesn't crash it
- throttling now writes on the tail (so two throttled `writeUpdate` calls will write one update, not two)
- room settings, punishments, and helptickets are now throttled
I wrote a `forceWrap` method to support break-word wrapping in table
cells for scavengers, but apparently code blocks need it too, so I'm
moving it to Utils.
Fixes#7854
* Utils: Visualize Maps/Sets in a cleaner fashion
* OK
* Update lib/utils.ts
Co-authored-by: Guangcong Luo <guangcongluo@gmail.com>
* Update lib/utils.ts
Co-authored-by: Guangcong Luo <guangcongluo@gmail.com>
* Update lib/utils.ts
Co-authored-by: Guangcong Luo <guangcongluo@gmail.com>
Co-authored-by: Guangcong Luo <guangcongluo@gmail.com>
Building from a fresh install currently fails since #7797
The problem is that `require('sucrase')` needs to be done _after_
sucrase is installed, which is a lot harder than it sounds.
It turns out 001f98b4f2 was wrong.
When urkerab asked why it `peek` wasn't awaited:
e91c4c5260 (commitcomment-41364837)
The answer was because clearing the buffer after peeking needed to
happen synchronous: if the buffer is written to after peeking but
before the buffer is cleared, that write is lost forever.
This just goes to show, if you do something subtle enough to require
type assertions, you should probably add a comment about what's going
on.
Fixes#7605
This also removes `BattleStream#start()` which is completely useless
API complication. A better implementation would properly forward
crashes between streams (maybe `pipeTo` should do this) but as it
stands, it's not doing anything.
* Lint arrow-body-style
* Lint prefer-object-spread
Object spread is faster _and_ more readable.
This also fixes a few unnecessary object clones.
* Enable no-parameter-properties
This isn't currently used, but this makes clear that it shouldn't be.
* Refactor more Promises to async/await
* Remove unnecessary code from getDataMoveHTML etc
* Lint prefer-string-starts-ends-with
* Stop using no-undef
According to the typescript-eslint FAQ, this is redundant with
TypeScript, and they're not wrong. This will save us from needing to
specify globals in two different places which will be nice.
We're skipping two major typescript-eslint versions, so there are a
bunch of changes here, including:
- it's catching a lot of things it didn't catch in the past, for
reasons unclear to me
- no-unused-vars has to be explicitly disabled in global-types now
- a lot of `ts-ignore`s were never necessary and have been fixed
- Crashlogger can now handle being thrown things that aren't errors.
This has never been a problem in the past, but to satisfy TypeScript
we might as well not die in a fire on the off chance someone tries to
`throw null` or something.
This adds new functions `stream.byChunk(bytes)`, `stream.byLine()` etc
which parse a `ReadStream` into an `ObjectReadStream<string>` which
can then be consumed with for-await.
Fixes#7195
`this.dex.deepClone` still exists as an alias to `Utils.deepClone` for
use in `data/`. I'll need to spend more time figuring out the correct
solution there.
Regular ReadStreams still can't; I now believe they shouldn't have a
"default" read method, and you should explicitly choose whether you
want to read "by chunks as they become available", "by chunks of a
specific line" or "by a delimiter".
So you would specifically use `stream.byLine()` or
`stream.byChunk([size])`, which would return an
`ObjectReadStream<string>`.
Inspired by #7195
Pointed out by @urkerab in e91c4c5260
I'm confused it ever worked in the past.
I also added `Symbol.asyncIterator` to make `for await` work correctly.
I'm still very annoyed by `Symbol`. Especially since the spec saw no
reason not to name the other function `next`, but calling it
`asyncIterator` instead of `[Symbol.asyncIterator] was too much of a
risk??? Complete bullshit that does nothing but break backwards
compatibility.
For some reason, my last try failed. The error just wasn't getting
caught. This is an attempt to make it not listen to the `'close'` event
if the `listen` function throws, which might work? I'll reboot to test
in Windows when I have time.
Refs #6873
This replaces the old approach with a new "clear everything except a
whitelist" approach, which should overall involve much less code and
lead to fewer bugs of the "the path changed for a module and I forgot
to update the uncache paths" variety.
I considered a lot of other approaches, but they seem to have more
flaws without any advantages in exchange for them. (We moved away
from `uncacheTree` because it only tracks the first require: there's
no way to get a full list of dependents for a module, only its first
dependent.)
A lot of Net functions returned Promises that would not reliably
resolve/reject if a Net request failed. This fixes it so they should
now all reliably reject on request failure.
(Yes, this fixes the ladder issues and memory leak in Main.)
Previously, ending a read stream was `stream.push(null)`, and ending a
write stream was `stream.end()`. This was often confusing, and so now,
these are consistently `stream.pushEnd()` and `stream.writeEnd()`.
This refactor already found a bug in which `stream.end()` was used
where `stream.push(null)` should have been.
Also in this refactor: By default, `pushError` ends the stream. You can
pass `true` as the second parameter if the error is recoverable (the
stream shouldn't end).
This is mostly just a follow up to #6342.
`prefer-optional-chaining` was turned on and fixed in every location it
complained in. The transformed function [0] looks expensive from a
glance but from skimming through the replaced sites it doesn't appear
to be ran in any important place, so it should be OK.
The linter improvements are:
- Increase linter performance
- Make `full-lint` and `lint` write to different caches so we
avoid overwriting their caches since they're different configs
- Change husky's hook to `npm run lint` so as to write to the
same cache
- Remove `@typescript-eslint/eslint-plugin-tslint` which is
essentially a wrapper to TSLint because the rules aren't worth
running another linter
- Convert `.eslintrc.json` and `.eslintrc-syntax.json` to two spaces
rather than four tabs to respect PS' `.editorconfig`
- Rename `fulllint` to `full-lint` to ease spelling it
[0] - https://pastie.io/mmtxpf.js (prettified)
PS apparently doesn't have gen-accurate Ability data for Pokémon in
Gen 3 that gained Abilities between Gen 3 and Gen 4 (like Pidgeot
still has Tangled Feet in Gen 3), but that will have to be left for
a future commit.
`server/chat-commands.js` is now a directory. It's been split into
`core`, `moderation`, and `admin`. `info` and `roomsettings` from
`chat-plugins` have also moved to `chat-commands`.
Some cleanup:
- Bot commands for inserting HTML into rooms like `/adduhtml` have been
moved from `info` into `admin`.
- `/a` has been renamed `/addline`, for clarity (and also moved from
`info` into `admin`).
- Room management commands like `/createroom` and `/roomintro` were
moved to `room-settings`
- `chat-commands/admin` has been TypeScripted
Dashycode had a bug that made it incorrectly encode non-ASCII
characters. I think this was fixed at some point but never made it
to PS's copy of Dashycode? Anyway, fixed now.
`import =` and `export =` are really only intended for backwards
compatibility with CommonJS. While I really don't like the new module
system TC39 has designed for us, it's what we should be using, and
consistency is important.
This is mostly a TypeScript refactor, but it does come with several
renames:
Dnsbl -> IPTools
Dnsbl.query -> IPTools.queryDnsbl
Dnsbl.reverse -> IPTools.getHost
When I originally wrote the Streams library, TypeScript-in-JS didn't
support generics. But now the library can have significantly nicer
typing, and so it now does.
PS prefers to keep battle streams open (for `/evalbattle`) until
manually ended, but this is confusing some other users. We now
automatically end streams unless the `keepAlive` option is set.
Fixes#5157
The old FS.writeUpdate throttle code was broken and unnecessarily
complicated. Since cancelable Promises don't exist and I was thinking
in Promises, I forgot about the existence of `clearTimeout`.
Rewriting with `clearTimeout` produces significantly more readable
code, which should no longer be bugged, and should in fact handle
complicated mixes of throttle times exactly the way I want them to
be handled.
(I rewrote this so many times in unpushed code, and each time turned
out unnecessarily complicated because I didn't remember `clearTimeout`
until now.)
PS's FS(...).writeUpdate(...) has a `throttle` option.
This changes it so it's possible to call it with the throttle on
sometimes and off sometimes, and "throttle off" will pre-empt "throttle
on" calls.
This contains a lot of minor refactors, but the main thing that's going
on here is that battle stream writes have been streamlined to be a lot
easier for others to use.
We even support:
./pokemon-showdown simulate-battle
which provides a stdio interface for anyone using any programming
language to simulate a battle.
Process Manager is now lib/process-manager.js
It's been entirely rewritten to reflect what I think a process manager
API should look like.
In particular, there are now two Process Managers, QueryProcessManager
and StreamProcessManager.
Pass QueryProcessManager a pure-ish query function (sync or async) that
takes a JSON value and returns a JSON value, and PM.query() will
execute that function in a subprocess, and return a Promise for its
return value.
StreamProcessManager is the same idea: Pass it a function to create an
ObjectReadWriteStream, and PM.createStream() will create a stream in a
subprocess and return a stream connected to it.
This is an update to match how Streams work: .read() returns a string,
and .readBuffer() returns a Buffer.
Being able to statically predict what type .read() will return is
really useful to TypeScript, in addition to being generally useful for
readability.
As a side benefit, readTextIfExists() is renamed readIfExists().
I've finally been sufficiently frustrated by Node's Streams API to
straight-up write my own.
This is what a Streams API looks like when you don't try to pretend
Promises don't exist. So much easier to use.
Dashycode is a library for encoding string data in restricted strings
in the [a-z0-9-] character set (namely, roomids).
...its main use is passing arbitrary string data in roomids, for HTML
rooms.