koffing 0.4.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +2 -2
- package/README.md +6 -131
- package/dist/index.d.ts +106 -0
- package/dist/index.js +431 -0
- package/dist/index.mjs +400 -0
- package/package.json +27 -32
- package/dist/koffing.js +0 -940
- package/dist/koffing.min.js +0 -1
- package/src/Pokemon.js +0 -174
- package/src/PokemonTeam.js +0 -80
- package/src/PokemonTeamSet.js +0 -54
- package/src/ShowdownParser.js +0 -281
- package/src/index.js +0 -76
package/LICENSE
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
MIT License
|
|
2
2
|
|
|
3
|
-
Copyright (c)
|
|
3
|
+
Copyright (c) 2022 Javi Aguilar
|
|
4
4
|
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
package/README.md
CHANGED
|
@@ -1,138 +1,13 @@
|
|
|
1
1
|
# Koffing
|
|
2
|
-
Koffing is a Pokemon Showdown Team parser that converts your strategies to
|
|
3
|
-
machine-readable JSON code.
|
|
4
2
|
|
|
5
|
-

|
|
6
4
|
|
|
7
|
-
|
|
8
|
-
one of the best ways to quickly try your strategies for the official Pokémon VGC Championships. This library is just
|
|
9
|
-
a parser for the teams generated by the [Showdown Team Builder](https://play.pokemonshowdown.com/teambuilder) exports.
|
|
10
|
-
|
|
11
|
-
This repository holds the source code for the library as well as the code for the Online Parser.
|
|
12
|
-
The [Online Parser](https://capsulemonsters.github.io/koffing), does not require you to download
|
|
13
|
-
any library or script, it is recommended if all you want is to sanitize, prettify or convert to JSON your
|
|
14
|
-
Showdown team exports.
|
|
5
|
+
Koffing is a Pokemon Showdown importable-syntax parser for JavaScript and TypeScript.
|
|
15
6
|
|
|
16
7
|
## Features
|
|
17
8
|
|
|
18
|
-
- Compatible with
|
|
19
|
-
-
|
|
20
|
-
-
|
|
21
|
-
- Sanitizes Showdown code (removing invalid data, applying max and mins values, etc.)
|
|
22
|
-
- Prettifies Showdown code (proper indentation, line breaks and sorting of the data, etc.)
|
|
23
|
-
- [Online Parser](https://capsulemonsters.github.io/koffing), which is using the library
|
|
24
|
-
featuring all the above mentioned.
|
|
25
|
-
|
|
26
|
-
## Installation
|
|
27
|
-
|
|
28
|
-
As a package:
|
|
29
|
-
```bash
|
|
30
|
-
npm i --save koffing
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
In the browser, using a CDN:
|
|
34
|
-
```html
|
|
35
|
-
<script src="https://cdn.rawgit.com/capsulemonsters/koffing/0.4.0/dist/koffing.min.js"></script>
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
### Usage
|
|
39
|
-
|
|
40
|
-
#### Modern Javascript (ES6+)
|
|
41
|
-
```js
|
|
42
|
-
"use strict";
|
|
43
|
-
|
|
44
|
-
import {Koffing} from 'koffing';
|
|
45
|
-
|
|
46
|
-
const teamCode = `
|
|
47
|
-
=== [gen7] Folder 1/Example Team ===
|
|
48
|
-
|
|
49
|
-
Smogon (Koffing) (F) @ Eviolite
|
|
50
|
-
Level: 5
|
|
51
|
-
Ability: Levitate
|
|
52
|
-
Shiny: Yes
|
|
53
|
-
Happiness: 255
|
|
54
|
-
EVs: 36 HP / 236 Def / 236 SpD
|
|
55
|
-
IVs: 31 HP / 30 Atk / 31 SpA / 30 SpD / 31 Spe
|
|
56
|
-
Bold Nature
|
|
57
|
-
- Will-O-Wisp
|
|
58
|
-
- Pain Split
|
|
59
|
-
- Sludge Bomb
|
|
60
|
-
- Fire Blast`;
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
let parsedTeam = Koffing.parse(teamCode);
|
|
64
|
-
|
|
65
|
-
// This will log a PokémonTeamSet object:
|
|
66
|
-
console.log(parsedTeam);
|
|
67
|
-
// Convert it back to the Showdown format (prettified):
|
|
68
|
-
console.log(parsedTeam.toShowdown());
|
|
69
|
-
// which is the same as:
|
|
70
|
-
console.log(parsedTeam.toString());
|
|
71
|
-
// and the same as:
|
|
72
|
-
console.log(parsedTeam + "");
|
|
73
|
-
// You can also convert the object to JSON:
|
|
74
|
-
console.log(parsedTeam.toJson());
|
|
75
|
-
// which is the same as:
|
|
76
|
-
console.log(Koffing.toJson(teamCode));
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
#### Web (ES5)
|
|
80
|
-
```html
|
|
81
|
-
<script src="dist/koffing.min.js"></script>
|
|
82
|
-
<script>
|
|
83
|
-
var teamCode = `=== [gen7] Folder 1/Example Team ===`;
|
|
84
|
-
var parsedTeam = Koffing.parse(teamCode);
|
|
85
|
-
console.log(parsedTeam);
|
|
86
|
-
|
|
87
|
-
// Note that the ShowdownParser class, which is used internally by the Koffing class
|
|
88
|
-
// is also exposed in the global scope:
|
|
89
|
-
console.log(new ShowdownParser(teamCode).parse());
|
|
90
|
-
</script>
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
#### NodeJS
|
|
94
|
-
```js
|
|
95
|
-
const Koffing = require('koffing').Koffing;
|
|
96
|
-
|
|
97
|
-
const teamCode = `=== [gen7] Folder 1/Example Team ===`;
|
|
98
|
-
let parsedTeam = Koffing.parse(teamCode);
|
|
99
|
-
console.log(parsedTeam);
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
### Class Reference
|
|
104
|
-
The `Koffing` class is basically a wrapper of the `ShowdownParser` class, the difference is that it can be used statically.
|
|
105
|
-
|
|
106
|
-
`ShowdownParser` class methods:
|
|
107
|
-
- `parse(): PokemonTeamSet`: Parses the Showdown code and returns a `PokemonTeamSet` object.
|
|
108
|
-
- `format(): String`: Parses the Showdown code and returns a prettified and sanitized version of it.
|
|
109
|
-
- `toString(): String`: Basically returns the internal Showdown code string as it is.
|
|
110
|
-
|
|
111
|
-
`Koffing` class methods:
|
|
112
|
-
- `static parse(showdownCode): PokemonTeamSet`: Wrapper for `ShowdownParser.prototype.parse()`
|
|
113
|
-
- `static format(showdownCode): String`: Wrapper for `ShowdownParser.prototype.format()`
|
|
114
|
-
- `static toJson(showdownCode): String`: Wrapper for `ShowdownParser.prototype.parse().toJson()`
|
|
115
|
-
- `static toShowdown(jsonCode): String`: Wrapper for `ShowdownParser.prototype.parse().toShowdown()`
|
|
116
|
-
|
|
117
|
-
## License
|
|
118
|
-
|
|
119
|
-
This software is copyrighted and licensed under the
|
|
120
|
-
[MIT license](https://github.com/capsulemonsters/koffing/LICENSE).
|
|
121
|
-
|
|
122
|
-
### Disclaimer
|
|
123
|
-
|
|
124
|
-
This software comes bundled with data and graphics extracted from the
|
|
125
|
-
Pokémon series of video games. Some terminology from the Pokémon franchise is
|
|
126
|
-
also necessarily used within the software itself. This is all the intellectual
|
|
127
|
-
property of Nintendo, Creatures, inc., and GAME FREAK, inc. and is protected by
|
|
128
|
-
various copyrights and trademarks.
|
|
129
|
-
|
|
130
|
-
The authors believe that the use of this intellectual property for a fan reference
|
|
131
|
-
is covered by fair use and that the software is significantly impaired without said
|
|
132
|
-
property included. Any use of this copyrighted property is at your own legal risk.
|
|
133
|
-
|
|
134
|
-
This software is not affiliated in any way with Nintendo,
|
|
135
|
-
Pokémon or any other game company.
|
|
9
|
+
- Compatible with Gen 9 Pokémon definitions
|
|
10
|
+
- Online parser
|
|
11
|
+
- JS/TS Library
|
|
136
12
|
|
|
137
|
-
|
|
138
|
-
https://github.com/capsulemonsters/koffing
|
|
13
|
+
> The full version of this README file can be found at https://github.com/itsjavi/koffing
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
type PokemonStats = {
|
|
2
|
+
hp: number;
|
|
3
|
+
atk: number;
|
|
4
|
+
def: number;
|
|
5
|
+
spa: number;
|
|
6
|
+
spd: number;
|
|
7
|
+
spe: number;
|
|
8
|
+
};
|
|
9
|
+
type PokemonGender = 'M' | 'F';
|
|
10
|
+
declare class Pokemon {
|
|
11
|
+
name: string | undefined;
|
|
12
|
+
nickname: string | undefined;
|
|
13
|
+
gender: PokemonGender | undefined;
|
|
14
|
+
item: string | undefined;
|
|
15
|
+
pokeball: string | undefined;
|
|
16
|
+
ability: string | undefined;
|
|
17
|
+
level: number | undefined;
|
|
18
|
+
shiny: boolean | undefined;
|
|
19
|
+
happiness: number | undefined;
|
|
20
|
+
nature: string | undefined;
|
|
21
|
+
evs: PokemonStats | undefined;
|
|
22
|
+
ivs: PokemonStats | undefined;
|
|
23
|
+
dynamaxLevel: number | undefined;
|
|
24
|
+
gigantamax: boolean | undefined;
|
|
25
|
+
teraType: string | undefined;
|
|
26
|
+
moves: string[];
|
|
27
|
+
static fromObject(obj: Pokemon | Record<string, any>): Pokemon;
|
|
28
|
+
toJson(indentation?: number): string;
|
|
29
|
+
toShowdown(): string;
|
|
30
|
+
toString(): string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
declare class PokemonTeam {
|
|
34
|
+
name: string;
|
|
35
|
+
format: string;
|
|
36
|
+
folder: string | undefined;
|
|
37
|
+
pokemon: Pokemon[];
|
|
38
|
+
constructor(format?: string, name?: string, folder?: string | undefined);
|
|
39
|
+
static fromObject(obj: PokemonTeam | Record<string, any>): PokemonTeam;
|
|
40
|
+
toJson(indentation?: number): string;
|
|
41
|
+
toShowdown(): string;
|
|
42
|
+
toString(): string;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
declare class PokemonTeamSet {
|
|
46
|
+
teams: PokemonTeam[];
|
|
47
|
+
constructor(teams?: PokemonTeam[]);
|
|
48
|
+
static fromObject(obj: PokemonTeamSet | Record<string, any>): PokemonTeamSet;
|
|
49
|
+
toJson(indentation?: number): string;
|
|
50
|
+
toShowdown(): string;
|
|
51
|
+
toString(): string;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
type ParserState = {
|
|
55
|
+
team: PokemonTeam | null;
|
|
56
|
+
pokemon: Pokemon | null;
|
|
57
|
+
};
|
|
58
|
+
/**
|
|
59
|
+
* Ported from Pokemon Showdown Client's exportTeam/importTeam functions.
|
|
60
|
+
*
|
|
61
|
+
* @see https://github.com/Zarel/Pokemon-Showdown-Client/blob/master/js/storage.js
|
|
62
|
+
*/
|
|
63
|
+
declare class ShowdownParser {
|
|
64
|
+
static regexes: Record<string, RegExp>;
|
|
65
|
+
code: string;
|
|
66
|
+
constructor(code: string);
|
|
67
|
+
parse(): PokemonTeamSet;
|
|
68
|
+
_parseTeam(line: string, team: PokemonTeam): void;
|
|
69
|
+
_parseNameLine(line: string, pokemon: Pokemon): void;
|
|
70
|
+
_parseEvsIvs(line: string, pokemon: Pokemon | any): boolean;
|
|
71
|
+
_parseKeyValuePairs(line: string, pokemon: Pokemon | any): boolean;
|
|
72
|
+
/**
|
|
73
|
+
* Saves the current state of the parsed team.
|
|
74
|
+
*/
|
|
75
|
+
_saveCurrent(teams: PokemonTeam[], current: ParserState): ShowdownParser;
|
|
76
|
+
/**
|
|
77
|
+
* Sanitizes and re-formats / prettifies the Showdown code
|
|
78
|
+
*/
|
|
79
|
+
format(): ShowdownParser;
|
|
80
|
+
/**
|
|
81
|
+
* @returns {string}
|
|
82
|
+
*/
|
|
83
|
+
toString(): string;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
type DataType = string | Pokemon | PokemonTeam | PokemonTeamSet | ShowdownParser;
|
|
87
|
+
declare class Koffing {
|
|
88
|
+
/**
|
|
89
|
+
* Converts from Showdown to a PokemonTeamSet object.
|
|
90
|
+
*/
|
|
91
|
+
static parse(data: DataType): Pokemon | PokemonTeam | PokemonTeamSet;
|
|
92
|
+
/**
|
|
93
|
+
* Prettifies and sanitizes the given Showdown code.
|
|
94
|
+
*/
|
|
95
|
+
static format(data: DataType): string;
|
|
96
|
+
/**
|
|
97
|
+
* Converts from Showdown to JSON code.
|
|
98
|
+
*/
|
|
99
|
+
static toJson(data: DataType): string;
|
|
100
|
+
/**
|
|
101
|
+
* Converts from JSON string or JSON object to Showdown code.
|
|
102
|
+
*/
|
|
103
|
+
static toShowdown(data: DataType | object): string;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export { Koffing, Pokemon, PokemonGender, PokemonStats, PokemonTeam, PokemonTeamSet, ShowdownParser };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,431 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var src_exports = {};
|
|
22
|
+
__export(src_exports, {
|
|
23
|
+
Koffing: () => Koffing,
|
|
24
|
+
Pokemon: () => Pokemon,
|
|
25
|
+
PokemonTeam: () => PokemonTeam,
|
|
26
|
+
PokemonTeamSet: () => PokemonTeamSet,
|
|
27
|
+
ShowdownParser: () => ShowdownParser
|
|
28
|
+
});
|
|
29
|
+
module.exports = __toCommonJS(src_exports);
|
|
30
|
+
|
|
31
|
+
// src/Pokemon.ts
|
|
32
|
+
var POKEMON_STAT_NAMES = ["HP", "Atk", "Def", "SpA", "SpD", "Spe"];
|
|
33
|
+
var Pokemon = class {
|
|
34
|
+
constructor() {
|
|
35
|
+
this.moves = [];
|
|
36
|
+
}
|
|
37
|
+
static fromObject(obj) {
|
|
38
|
+
const p = new Pokemon();
|
|
39
|
+
p.name = obj.name;
|
|
40
|
+
p.nickname = obj.nickname;
|
|
41
|
+
p.gender = obj.gender;
|
|
42
|
+
p.item = obj.item;
|
|
43
|
+
p.ability = obj.ability;
|
|
44
|
+
p.level = obj.level;
|
|
45
|
+
p.shiny = obj.shiny;
|
|
46
|
+
p.happiness = obj.happiness;
|
|
47
|
+
p.nature = obj.nature;
|
|
48
|
+
p.evs = obj.evs;
|
|
49
|
+
p.ivs = obj.ivs;
|
|
50
|
+
p.teraType = obj.teraType;
|
|
51
|
+
p.dynamaxLevel = obj.dynamaxLevel;
|
|
52
|
+
p.gigantamax = obj.gigantamax;
|
|
53
|
+
p.pokeball = obj.pokeball;
|
|
54
|
+
p.moves = Array.isArray(obj.moves) ? obj.moves : [];
|
|
55
|
+
return p;
|
|
56
|
+
}
|
|
57
|
+
toJson(indentation = 2) {
|
|
58
|
+
return JSON.stringify(this, null, indentation);
|
|
59
|
+
}
|
|
60
|
+
toShowdown() {
|
|
61
|
+
let str = "";
|
|
62
|
+
if (this.nickname) {
|
|
63
|
+
str += `${this.nickname} (${this.name})`;
|
|
64
|
+
} else {
|
|
65
|
+
str += `${this.name}`;
|
|
66
|
+
}
|
|
67
|
+
if (this.gender && this.gender.match(/^[MF]$/i)) {
|
|
68
|
+
str += ` (${this.gender.toUpperCase()})`;
|
|
69
|
+
}
|
|
70
|
+
if (this.item) {
|
|
71
|
+
str += ` @ ${this.item}`;
|
|
72
|
+
}
|
|
73
|
+
str += "\n";
|
|
74
|
+
if (this.ability) {
|
|
75
|
+
str += `Ability: ${this.ability}
|
|
76
|
+
`;
|
|
77
|
+
}
|
|
78
|
+
if (!Number.isNaN(this.level)) {
|
|
79
|
+
str += `Level: ${this.level}
|
|
80
|
+
`;
|
|
81
|
+
}
|
|
82
|
+
if (this.shiny === true) {
|
|
83
|
+
str += `Shiny: Yes
|
|
84
|
+
`;
|
|
85
|
+
}
|
|
86
|
+
if (!Number.isNaN(this.happiness)) {
|
|
87
|
+
str += `Happiness: ${this.happiness}
|
|
88
|
+
`;
|
|
89
|
+
}
|
|
90
|
+
if (this.pokeball) {
|
|
91
|
+
str += `Pokeball: ${this.pokeball}
|
|
92
|
+
`;
|
|
93
|
+
}
|
|
94
|
+
if (!Number.isNaN(this.dynamaxLevel)) {
|
|
95
|
+
str += `Dynamax Level: ${this.dynamaxLevel}
|
|
96
|
+
`;
|
|
97
|
+
}
|
|
98
|
+
if (this.gigantamax === true) {
|
|
99
|
+
str += `Gigantamax: Yes
|
|
100
|
+
`;
|
|
101
|
+
}
|
|
102
|
+
if (this.teraType) {
|
|
103
|
+
str += `Tera Type: ${this.teraType}
|
|
104
|
+
`;
|
|
105
|
+
}
|
|
106
|
+
if (this.evs) {
|
|
107
|
+
const evs = this.evs;
|
|
108
|
+
str += `EVs: ` + POKEMON_STAT_NAMES.filter(function(prop) {
|
|
109
|
+
return !isNaN(evs[prop.toLowerCase()]);
|
|
110
|
+
}).map(function(prop) {
|
|
111
|
+
const val = evs[prop.toLowerCase()];
|
|
112
|
+
return `${val} ${prop}`;
|
|
113
|
+
}).join(" / ") + "\n";
|
|
114
|
+
}
|
|
115
|
+
if (this.nature) {
|
|
116
|
+
str += `${this.nature} Nature
|
|
117
|
+
`;
|
|
118
|
+
}
|
|
119
|
+
if (this.ivs) {
|
|
120
|
+
const ivs = this.ivs;
|
|
121
|
+
str += `IVs: ` + POKEMON_STAT_NAMES.filter(function(prop) {
|
|
122
|
+
return !isNaN(ivs[prop.toLowerCase()]);
|
|
123
|
+
}).map(function(prop) {
|
|
124
|
+
const val = ivs[prop.toLowerCase()];
|
|
125
|
+
return `${val} ${prop}`;
|
|
126
|
+
}).join(" / ") + "\n";
|
|
127
|
+
}
|
|
128
|
+
if (this.moves) {
|
|
129
|
+
str += this.moves.map(function(move) {
|
|
130
|
+
return `- ${move}`;
|
|
131
|
+
}).join("\n") + "\n";
|
|
132
|
+
}
|
|
133
|
+
return str.trim();
|
|
134
|
+
}
|
|
135
|
+
toString() {
|
|
136
|
+
return this.toShowdown();
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
// src/PokemonTeam.ts
|
|
141
|
+
var PokemonTeam = class {
|
|
142
|
+
constructor(format = "gen9", name = "Untitled", folder = void 0) {
|
|
143
|
+
this.pokemon = [];
|
|
144
|
+
this.name = name;
|
|
145
|
+
this.format = format;
|
|
146
|
+
this.folder = folder;
|
|
147
|
+
}
|
|
148
|
+
static fromObject(obj) {
|
|
149
|
+
const team = new PokemonTeam();
|
|
150
|
+
team.name = obj.name;
|
|
151
|
+
team.format = obj.format;
|
|
152
|
+
team.folder = obj.folder;
|
|
153
|
+
team.pokemon = obj.pokemon ? obj.pokemon.map(function(pokemon) {
|
|
154
|
+
return Pokemon.fromObject(pokemon);
|
|
155
|
+
}) : [];
|
|
156
|
+
return team;
|
|
157
|
+
}
|
|
158
|
+
toJson(indentation = 2) {
|
|
159
|
+
return JSON.stringify(this, null, indentation);
|
|
160
|
+
}
|
|
161
|
+
toShowdown() {
|
|
162
|
+
const name = this.folder ? `${this.folder}/${this.name}` : this.name;
|
|
163
|
+
let str = `=== [${this.format}] ${name} ===
|
|
164
|
+
|
|
165
|
+
`;
|
|
166
|
+
str += this.pokemon.map(function(p) {
|
|
167
|
+
return p.toString();
|
|
168
|
+
}).join("\n\n");
|
|
169
|
+
return str.trim();
|
|
170
|
+
}
|
|
171
|
+
toString() {
|
|
172
|
+
return this.toShowdown();
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
// src/PokemonTeamSet.ts
|
|
177
|
+
var PokemonTeamSet = class {
|
|
178
|
+
constructor(teams = []) {
|
|
179
|
+
this.teams = teams;
|
|
180
|
+
}
|
|
181
|
+
static fromObject(obj) {
|
|
182
|
+
const teamSet = new PokemonTeamSet();
|
|
183
|
+
teamSet.teams = obj.teams ? obj.teams.map(function(team) {
|
|
184
|
+
return PokemonTeam.fromObject(team);
|
|
185
|
+
}) : [];
|
|
186
|
+
return teamSet;
|
|
187
|
+
}
|
|
188
|
+
toJson(indentation = 2) {
|
|
189
|
+
return JSON.stringify(this, null, indentation);
|
|
190
|
+
}
|
|
191
|
+
toShowdown() {
|
|
192
|
+
return this.teams.map(function(p) {
|
|
193
|
+
return p.toString();
|
|
194
|
+
}).join("\n\n").trim();
|
|
195
|
+
}
|
|
196
|
+
toString() {
|
|
197
|
+
return this.toShowdown();
|
|
198
|
+
}
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
// src/ShowdownParser.ts
|
|
202
|
+
var clamp = (num, min, max) => {
|
|
203
|
+
if (Number.isNaN(num)) {
|
|
204
|
+
return min;
|
|
205
|
+
}
|
|
206
|
+
return Math.min(Math.max(num, min), max);
|
|
207
|
+
};
|
|
208
|
+
var _ShowdownParser = class {
|
|
209
|
+
constructor(code) {
|
|
210
|
+
this.code = code.toString().trim();
|
|
211
|
+
}
|
|
212
|
+
parse() {
|
|
213
|
+
const regexes = _ShowdownParser.regexes;
|
|
214
|
+
const teams = [];
|
|
215
|
+
const current = {
|
|
216
|
+
team: null,
|
|
217
|
+
pokemon: null
|
|
218
|
+
};
|
|
219
|
+
const lines = this.code.trim().split("\n").map(function(line) {
|
|
220
|
+
return line.trim();
|
|
221
|
+
});
|
|
222
|
+
lines.forEach((line) => {
|
|
223
|
+
if (line.match(regexes.team)) {
|
|
224
|
+
current.team = new PokemonTeam();
|
|
225
|
+
this._parseTeam(line, current.team);
|
|
226
|
+
teams.push(current.team);
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
if (line === "" || line.match(/^[- ]+$/)) {
|
|
230
|
+
this._saveCurrent(teams, current);
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
if (!current.pokemon) {
|
|
234
|
+
current.pokemon = new Pokemon();
|
|
235
|
+
this._parseNameLine(line, current.pokemon);
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
if (this._parseKeyValuePairs(line, current.pokemon)) {
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
if (this._parseEvsIvs(line, current.pokemon)) {
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
if (current.pokemon.moves.length < 4 && line.match(regexes.move)) {
|
|
245
|
+
const moveMatches = regexes.move.exec(line);
|
|
246
|
+
if (moveMatches !== null) {
|
|
247
|
+
current.pokemon.moves.push(moveMatches[1].trim());
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
});
|
|
251
|
+
this._saveCurrent(teams, current);
|
|
252
|
+
return new PokemonTeamSet(teams);
|
|
253
|
+
}
|
|
254
|
+
_parseTeam(line, team) {
|
|
255
|
+
const rg = _ShowdownParser.regexes;
|
|
256
|
+
const teamDataMatches = rg.team.exec(line);
|
|
257
|
+
if (teamDataMatches && teamDataMatches.length >= 2) {
|
|
258
|
+
const teamNames = teamDataMatches[2].split("/");
|
|
259
|
+
let teamName, teamFolder;
|
|
260
|
+
if (teamNames.length > 1) {
|
|
261
|
+
teamFolder = teamNames.shift();
|
|
262
|
+
teamName = teamNames.join("/");
|
|
263
|
+
} else {
|
|
264
|
+
teamName = teamDataMatches[2];
|
|
265
|
+
}
|
|
266
|
+
team.format = teamDataMatches[1].trim();
|
|
267
|
+
team.name = teamName.trim();
|
|
268
|
+
team.folder = teamFolder ? teamFolder.trim() : void 0;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
_parseNameLine(line, pokemon) {
|
|
272
|
+
const rg = _ShowdownParser.regexes;
|
|
273
|
+
if (line.match(rg.nickname_name)) {
|
|
274
|
+
const nameMatches = rg.nickname_name.exec(line);
|
|
275
|
+
if (nameMatches) {
|
|
276
|
+
pokemon.nickname = nameMatches[1].trim();
|
|
277
|
+
pokemon.name = nameMatches[2].trim();
|
|
278
|
+
}
|
|
279
|
+
} else if (line.match(rg.name)) {
|
|
280
|
+
const nameMatches = rg.name.exec(line);
|
|
281
|
+
if (nameMatches) {
|
|
282
|
+
pokemon.name = nameMatches[1].trim();
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
if (line.match(rg.gender)) {
|
|
286
|
+
const genderMatches = rg.gender.exec(line);
|
|
287
|
+
if (genderMatches) {
|
|
288
|
+
pokemon.gender = genderMatches[1].toUpperCase().trim();
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
if (line.match(rg.item)) {
|
|
292
|
+
const itemMatches = rg.item.exec(line);
|
|
293
|
+
if (itemMatches) {
|
|
294
|
+
pokemon.item = itemMatches[1].trim();
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
_parseEvsIvs(line, pokemon) {
|
|
299
|
+
const rg = _ShowdownParser.regexes;
|
|
300
|
+
if (line.match(rg.eivs)) {
|
|
301
|
+
const data = rg.eivs.exec(line);
|
|
302
|
+
if (data === null) {
|
|
303
|
+
return false;
|
|
304
|
+
}
|
|
305
|
+
const prop = data[1].toLowerCase();
|
|
306
|
+
const values = data[2].split("/");
|
|
307
|
+
const limit = prop === "evs" ? 255 : 31;
|
|
308
|
+
values.forEach(function(stat) {
|
|
309
|
+
const statData = rg.eivs_value.exec(stat.trim().toLowerCase());
|
|
310
|
+
if (!statData) {
|
|
311
|
+
console.error("Invalid syntax for " + prop + ": " + stat);
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
if (!pokemon[prop]) {
|
|
315
|
+
pokemon[prop] = {};
|
|
316
|
+
}
|
|
317
|
+
pokemon[prop][statData[2]] = clamp(parseInt(statData[1]), 0, limit);
|
|
318
|
+
});
|
|
319
|
+
return true;
|
|
320
|
+
}
|
|
321
|
+
return false;
|
|
322
|
+
}
|
|
323
|
+
_parseKeyValuePairs(line, pokemon) {
|
|
324
|
+
const propNames = [
|
|
325
|
+
"nature",
|
|
326
|
+
"ability",
|
|
327
|
+
"level",
|
|
328
|
+
"shiny",
|
|
329
|
+
"happiness",
|
|
330
|
+
"pokeball",
|
|
331
|
+
"dynamaxLevel",
|
|
332
|
+
"gigantamax",
|
|
333
|
+
"teraType"
|
|
334
|
+
];
|
|
335
|
+
return propNames.some(function(key) {
|
|
336
|
+
const matches = _ShowdownParser.regexes[key].exec(line);
|
|
337
|
+
if (matches === null) {
|
|
338
|
+
return false;
|
|
339
|
+
}
|
|
340
|
+
let value = matches[1].trim();
|
|
341
|
+
if (key === "happiness") {
|
|
342
|
+
value = clamp(parseInt(value), 0, 255);
|
|
343
|
+
} else if (key === "level") {
|
|
344
|
+
value = clamp(parseInt(value), 1, 100);
|
|
345
|
+
} else if (key === "dynamaxLevel") {
|
|
346
|
+
value = clamp(parseInt(value), 0, 10);
|
|
347
|
+
} else if (key.match(/^(shiny|gigantamax)$/i)) {
|
|
348
|
+
value = value.match(/yes/i) !== null ? true : void 0;
|
|
349
|
+
}
|
|
350
|
+
pokemon[key] = value;
|
|
351
|
+
return true;
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
_saveCurrent(teams, current) {
|
|
355
|
+
if (!current.team) {
|
|
356
|
+
current.team = new PokemonTeam();
|
|
357
|
+
teams.push(current.team);
|
|
358
|
+
}
|
|
359
|
+
if (current.pokemon) {
|
|
360
|
+
current.team.pokemon.push(current.pokemon);
|
|
361
|
+
current.pokemon = null;
|
|
362
|
+
}
|
|
363
|
+
return this;
|
|
364
|
+
}
|
|
365
|
+
format() {
|
|
366
|
+
this.code = this.parse().toString();
|
|
367
|
+
return this;
|
|
368
|
+
}
|
|
369
|
+
toString() {
|
|
370
|
+
return this.code;
|
|
371
|
+
}
|
|
372
|
+
};
|
|
373
|
+
var ShowdownParser = _ShowdownParser;
|
|
374
|
+
ShowdownParser.regexes = {
|
|
375
|
+
team: /^===\s+\[(.*)\]\s+(.*)\s+===$/,
|
|
376
|
+
nickname_name: /^([^()=@]*)\s+\(([^()=@]{2,})\)/i,
|
|
377
|
+
name: /^([^()=@]{2,})/i,
|
|
378
|
+
gender: /\((F|M)\)/i,
|
|
379
|
+
item: /@\s?(.*)$/i,
|
|
380
|
+
eivs: /^([EI]Vs):\s?(.*)$/i,
|
|
381
|
+
eivs_value: /^([0-9]+)\s+(hp|atk|def|spa|spd|spe)$/i,
|
|
382
|
+
move: /^[-~]\s?(.*)$/i,
|
|
383
|
+
nature: /^(.*)\s+Nature$/,
|
|
384
|
+
ability: /^(?:Ability|Trait):\s?(.*)$/i,
|
|
385
|
+
level: /^Level:\s?([0-9]{1,3})$/i,
|
|
386
|
+
shiny: /^Shiny:\s?(Yes|No)$/i,
|
|
387
|
+
happiness: /^(?:Happiness|Friendship):\s?([0-9]{1,3})$/i,
|
|
388
|
+
pokeball: /^(?:Pokeball|Ball):\s?(.*)$/i,
|
|
389
|
+
dynamaxLevel: /^Dynamax Level:\s?([0-9]{1,2})$/i,
|
|
390
|
+
gigantamax: /^Gigantamax:\s?(Yes|No)$/i,
|
|
391
|
+
teraType: /^Tera Type:\s?(.*)$/i
|
|
392
|
+
};
|
|
393
|
+
|
|
394
|
+
// src/Koffing.ts
|
|
395
|
+
var Koffing = class {
|
|
396
|
+
static parse(data) {
|
|
397
|
+
if (data instanceof PokemonTeamSet || data instanceof PokemonTeam || data instanceof Pokemon) {
|
|
398
|
+
return data;
|
|
399
|
+
}
|
|
400
|
+
if (data instanceof ShowdownParser) {
|
|
401
|
+
return data.parse();
|
|
402
|
+
}
|
|
403
|
+
return new ShowdownParser(data).parse();
|
|
404
|
+
}
|
|
405
|
+
static format(data) {
|
|
406
|
+
return this.parse(data).toShowdown();
|
|
407
|
+
}
|
|
408
|
+
static toJson(data) {
|
|
409
|
+
return this.parse(data).toJson();
|
|
410
|
+
}
|
|
411
|
+
static toShowdown(data) {
|
|
412
|
+
if (data instanceof PokemonTeamSet || data instanceof PokemonTeam || data instanceof Pokemon) {
|
|
413
|
+
return data.toShowdown();
|
|
414
|
+
}
|
|
415
|
+
if (data instanceof ShowdownParser) {
|
|
416
|
+
return data.parse().toShowdown();
|
|
417
|
+
}
|
|
418
|
+
if (typeof data === "string") {
|
|
419
|
+
data = JSON.parse(data);
|
|
420
|
+
}
|
|
421
|
+
return PokemonTeamSet.fromObject(data).toShowdown();
|
|
422
|
+
}
|
|
423
|
+
};
|
|
424
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
425
|
+
0 && (module.exports = {
|
|
426
|
+
Koffing,
|
|
427
|
+
Pokemon,
|
|
428
|
+
PokemonTeam,
|
|
429
|
+
PokemonTeamSet,
|
|
430
|
+
ShowdownParser
|
|
431
|
+
});
|