@eveshipfit/dogma-engine 11.0.1 → 11.2.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/README.md CHANGED
@@ -112,6 +112,37 @@ To make rendering a fit easier, these are calculated by this library, and presen
112
112
  Their identifier is always a negative value, to visually separate them.
113
113
  What additional attributes exist are defined in [EVEShipFit/sde-patched](https://github.com/EVEShipFit/sde-patched) repository.
114
114
 
115
+ ## Validation
116
+
117
+ `validate()` checks if the fit violates any rules that would prevent you from flying it in-game.
118
+ It returns the violations, grouped by the kind of rule and, within a kind, in the order of `items`.
119
+ An empty list means the fit breaks no rules.
120
+
121
+ Each violation has:
122
+
123
+ - `target`: what the rule is about.
124
+ - `ship`, for what the ship carries as a whole.
125
+ - `item`, with the `index` into `items`.
126
+ - `charge`, with the `index` into `items` of the item holding it.
127
+ - `rule`: the rule, and the values that failed it. `type` says which:
128
+ - `resource`: `resource` ran out, `used` of `available`.
129
+ One of `cpu`, `powergrid`, `calibration`, `drone_bay`, `drone_bandwidth`, `launched_drones`, `fighter_bay`, `fighter_tubes`, `light_fighter_tubes`, `support_fighter_tubes`, `heavy_fighter_tubes`, `cargo_bay` or `charge_capacity`.
130
+ - `slots`: more items in the `slot` rack than the ship has, `used` of `available`.
131
+ One of `high`, `medium`, `low`, `rig`, `subsystem`, `service`, `turret` or `launcher`; the last two are hardpoints a weapon takes on top of its slot.
132
+ - `wrong_slot`: the item belongs in the `expected` rack.
133
+ - `slot_taken`: another item of the fit is in this slot too.
134
+ - `wrong_slot_index`: an implant or booster outside the slot it occupies, which is `expected`.
135
+ - `subsystem_taken`: another subsystem covers the same part of the ship.
136
+ - `skill`: the character is missing `type_id`, or has it at `level` where the item asks for `required`.
137
+ - `rig_size`: a rig of size `item` where the `ship` takes another.
138
+ - `ship_restricted`: the item cannot go on this ship at all.
139
+ - `capital_item`: a capital item on a ship that is not a capital.
140
+ - `max_group`: `used` of `group_id` are `limit` (`fitted`, `online` or `active`), where `allowed` may be.
141
+ This is what keeps a second propulsion module from running: an afterburner and a microwarpdrive share a group.
142
+ - `max_type`: `used` of `type_id` are fitted, where `allowed` may be.
143
+ - `charge_group`: a charge of a group the module does not take.
144
+ - `charge_size`: a charge of size `charge` where the `module` takes another.
145
+
115
146
  ## Usage
116
147
 
117
148
  The engine is published for Rust, Javascript and Python; all three calculate the same way.
@@ -131,7 +162,7 @@ cargo add esf-dogma-engine esf-data
131
162
 
132
163
  ```rust
133
164
  use esf_data::{InfoSde, Sde};
134
- use esf_dogma_engine::{Fit, Options, beacon, calculate};
165
+ use esf_dogma_engine::{Fit, Options, beacon, calculate, validate};
135
166
 
136
167
  let bytes = std::fs::read("sde.dat")?;
137
168
  let sde = Sde::new(&bytes)?;
@@ -157,6 +188,9 @@ let calculation = calculate(&info, &fit, &Options::default());
157
188
  let with_sources = calculate(&info, &fit, &Options { sources: true, ..Default::default() });
158
189
  // Or if you have a beacon in space (like wormhole effects):
159
190
  let with_beacon = calculate(&info, &Fit { incoming: beacon(&info, beacon_type_id), ..fit }, &Options::default());
191
+
192
+ // What EVE would not let you fly:
193
+ let violations = validate(&info, &fit, &calculation);
160
194
  ```
161
195
 
162
196
  ### Javascript (WebAssembly)
@@ -165,15 +199,24 @@ The WebAssembly variant is published on npm as
165
199
  [`@eveshipfit/dogma-engine`](https://www.npmjs.com/package/@eveshipfit/dogma-engine).
166
200
  [`@eveshipfit/sde`](https://www.npmjs.com/package/@eveshipfit/sde) ships `sde.dat` in its `dist` folder; serve or bundle that file.
167
201
 
202
+ The package is built for bundlers (Vite, webpack 5, ...), which load the `.wasm` themselves.
203
+
168
204
  ```bash
169
205
  npm install @eveshipfit/dogma-engine @eveshipfit/sde
170
206
  ```
171
207
 
172
208
  ```js
173
- import init, { init as initPanicHook, load_sde, load_eft, calculate, beacon } from "@eveshipfit/dogma-engine";
174
-
175
- await init();
176
- initPanicHook();
209
+ import {
210
+ init,
211
+ load_sde,
212
+ load_eft,
213
+ save_eft,
214
+ calculate,
215
+ validate,
216
+ beacon,
217
+ } from "@eveshipfit/dogma-engine";
218
+
219
+ init();
177
220
 
178
221
  const sde = await fetch("/sde.dat").then((response) => response.arrayBuffer());
179
222
  const buildNumber = load_sde(new Uint8Array(sde));
@@ -190,6 +233,11 @@ const withSources = calculate(fit, { sources: true });
190
233
  const withBeacon = calculate({ ...fit, incoming: beacon(beaconTypeId) });
191
234
  /* Or if you have an EFT, the text format EVE copies a fit to the clipboard in: */
192
235
  const imported = calculate(load_eft("[Rifter, My Rifter]\n200mm AutoCannon I"));
236
+ /* And to write a fit back out as EFT: */
237
+ const eft = save_eft(fit);
238
+
239
+ /* What EVE would not let you fly; it calculates the fit itself: */
240
+ const violations = validate(fit);
193
241
  ```
194
242
 
195
243
  ### Python
@@ -228,6 +276,11 @@ with_sources = dogma.calculate(fit, {"sources": True})
228
276
  with_beacon = dogma.calculate({**fit, "incoming": dogma.beacon(beacon_type_id)})
229
277
  # Or if you have an EFT, the text format EVE copies a fit to the clipboard in:
230
278
  imported = dogma.calculate(dogma.load_eft("[Rifter, My Rifter]\n200mm AutoCannon I"))
279
+ # And to write a fit back out as EFT:
280
+ eft = dogma.save_eft(fit)
281
+
282
+ # What EVE would not let you fly; it calculates the fit itself:
283
+ violations = dogma.validate(fit)
231
284
  ```
232
285
 
233
286
  Fits and calculations are plain dicts, typed with `TypedDict` in `esf_dogma_engine.types`.
@@ -267,6 +320,13 @@ printf '[Nergal, Spool]\nLight Entropic Disintegrator II, Occult S\n' \
267
320
 
268
321
  It prints a table on a terminal and JSON otherwise; see `--help` for the rest.
269
322
 
323
+ Or to write the fit back out as EFT, instead of calculating it:
324
+
325
+ ```bash
326
+ printf '[Nergal, Spool]\nLight Entropic Disintegrator II, Occult S\n' \
327
+ | cargo run --release -p esf-cli -- --eft
328
+ ```
329
+
270
330
  The regression suite reads the same paths; set `ESF_SDE` and `ESF_NAMES` to point it elsewhere.
271
331
 
272
332
  ## Regression
@@ -1,23 +1,448 @@
1
1
  /* tslint:disable */
2
2
  /* eslint-disable */
3
+ /**
4
+ * A charge loaded in a module.
5
+ */
6
+ export interface Charge {
7
+ /**
8
+ * The type id of the charge.
9
+ */
10
+ type_id: number;
11
+ }
12
+
13
+ /**
14
+ * A module, drone, fighter squadron, implant, booster or item in cargo.
15
+ */
16
+ export interface FitItem {
17
+ /**
18
+ * The type id of the item.
19
+ */
20
+ type_id: number;
21
+ /**
22
+ * Where the item is.
23
+ */
24
+ slot: Slot;
25
+ /**
26
+ * 1 for modules. Stack size for drones, fighters and cargo; for fighters
27
+ * in a tube, the size of the squadron.
28
+ */
29
+ quantity?: number;
30
+ /**
31
+ * The state asked for; the calculation lowers it when the item cannot
32
+ * reach it.
33
+ */
34
+ state: State;
35
+ /**
36
+ * The charge loaded in the module, if any.
37
+ */
38
+ charge?: Charge;
39
+ /**
40
+ * Only for mutated modules and drones.
41
+ */
42
+ mutation?: Mutation;
43
+ /**
44
+ * Only for fighters: the abilities used, by effect id. `None` uses the
45
+ * abilities the fighter uses by default.
46
+ */
47
+ fighter_abilities?: number[];
48
+ /**
49
+ * Only for boosters: the side effects rolled, by effect id. Empty means
50
+ * none.
51
+ */
52
+ booster_side_effects?: number[];
53
+ /**
54
+ * How far a module whose bonus grows every cycle has spooled.
55
+ * Only per-second stats use it; volley is always unspooled.
56
+ * `None` is fully spooled.
57
+ */
58
+ spool?: Spool;
59
+ }
60
+
61
+ /**
62
+ * A projected buff (like command bursts).
63
+ */
64
+ export interface ProjectedBuff {
65
+ /**
66
+ * Which buff, as `dbuffCollections` in the SDE numbers them.
67
+ */
68
+ id: number;
69
+ /**
70
+ * How strong it is, in whatever the buff's operation reads.
71
+ */
72
+ value: number;
73
+ }
74
+
75
+ /**
76
+ * A projected dogma effect.
77
+ */
78
+ export interface ProjectedEffect {
79
+ /**
80
+ * The type the effect belongs to.
81
+ */
82
+ type_id: number;
83
+ /**
84
+ * Which effect, as `dogmaEffects` in the SDE numbers them.
85
+ */
86
+ effect_id: number;
87
+ /**
88
+ * Every attribute and its value the effect reads.
89
+ */
90
+ attributes?: Map<number, number> | Record<number, number>;
91
+ }
92
+
93
+ /**
94
+ * A rack of slots, or a hardpoint a weapon needs.
95
+ */
96
+ export type SlotKind = "high" | "medium" | "low" | "rig" | "subsystem" | "service" | "turret" | "launcher";
97
+
98
+ /**
99
+ * A resource the ship only has so much of.
100
+ */
101
+ export type Resource = "cpu" | "powergrid" | "calibration" | "drone_bay" | "drone_bandwidth" | "launched_drones" | "fighter_bay" | "fighter_tubes" | "light_fighter_tubes" | "support_fighter_tubes" | "heavy_fighter_tubes" | "cargo_bay" | "charge_capacity";
102
+
103
+ /**
104
+ * A rule of EVE's, and the values that failed it.
105
+ *
106
+ * What an item would accept instead is not repeated here; it is on the item
107
+ * itself, as `chargeGroup1`, `canFitShipType1` and the like.
108
+ */
109
+ export type Rule = { type: "resource"; resource: Resource; used: number; available: number } | { type: "slots"; slot: SlotKind; used: number; available: number } | { type: "wrong_slot"; expected: SlotKind } | { type: "slot_taken" } | { type: "wrong_slot_index"; expected: number } | { type: "subsystem_taken" } | { type: "skill"; type_id: number; required: number; level: number } | { type: "rig_size"; ship: number; item: number } | { type: "ship_restricted" } | { type: "capital_item" } | { type: "structure_item" } | { type: "ship_item" } | { type: "max_group"; group_id: number; limit: GroupLimit; used: number; allowed: number } | { type: "max_type"; type_id: number; used: number; allowed: number } | { type: "charge_group" } | { type: "charge_size"; module: number; charge: number };
110
+
111
+ /**
112
+ * A ship, what is fitted to it, and the character flying it.
113
+ */
114
+ export interface Fit {
115
+ /**
116
+ * Only for display; the calculation does not use it.
117
+ */
118
+ name?: string;
119
+ /**
120
+ * The ship.
121
+ */
122
+ ship: Ship;
123
+ /**
124
+ * Modules, drones, fighters, implants, boosters and cargo.
125
+ */
126
+ items: FitItem[];
127
+ /**
128
+ * The character flying the ship.
129
+ */
130
+ character?: Character;
131
+ /**
132
+ * Where the ship is.
133
+ */
134
+ environment?: Environment;
135
+ /**
136
+ * What projections to apply on this fit.
137
+ */
138
+ incoming?: Projection;
139
+ }
140
+
141
+ /**
142
+ * How a modifier changes an attribute. They are applied in this order.
143
+ */
144
+ export type EffectOperator = "pre_assign" | "pre_mul" | "pre_div" | "mod_add" | "mod_sub" | "post_mul" | "post_div" | "post_percent" | "post_assign";
145
+
146
+ /**
147
+ * How a module or drone was mutated.
148
+ */
149
+ export interface Mutation {
150
+ /**
151
+ * The type id of the item before it was mutated.
152
+ */
153
+ base: number;
154
+ /**
155
+ * The rolled value of each mutated attribute, by attribute id.
156
+ */
157
+ attributes?: Map<number, number> | Record<number, number>;
158
+ }
159
+
160
+ /**
161
+ * How far a module has spooled.
162
+ */
163
+ export type Spool = { multiplier_bonus: number };
164
+
165
+ /**
166
+ * How incoming damage is split over the four damage types. Only the ratio
167
+ * matters; the calculation scales the four to add up to one.
168
+ */
169
+ export interface DamageProfile {
170
+ /**
171
+ * EM damage.
172
+ */
173
+ em?: number;
174
+ /**
175
+ * Explosive damage.
176
+ */
177
+ explosive?: number;
178
+ /**
179
+ * Kinetic damage.
180
+ */
181
+ kinetic?: number;
182
+ /**
183
+ * Thermal damage.
184
+ */
185
+ thermal?: number;
186
+ }
187
+
188
+ /**
189
+ * One attribute, before and after the effects on it.
190
+ */
191
+ export interface AttributeValue {
192
+ /**
193
+ * The value from the SDE.
194
+ */
195
+ base: number;
196
+ /**
197
+ * The value after every effect is applied.
198
+ */
199
+ value: number;
200
+ /**
201
+ * In the order pass 3 applied them; empty unless `Options::sources` is set.
202
+ */
203
+ sources?: Source[];
204
+ }
205
+
206
+ /**
207
+ * One modifier on an attribute, and where it came from.
208
+ */
209
+ export interface Source {
210
+ /**
211
+ * The object the effect belongs to.
212
+ */
213
+ from: SourceRef;
214
+ /**
215
+ * The effect that holds the modifier; `None` for a buff, which has none.
216
+ */
217
+ effect_id: number | undefined;
218
+ /**
219
+ * The attribute on the source that holds `value`; `None` for a buff,
220
+ * which carries its own strength.
221
+ */
222
+ source_attribute_id: number | undefined;
223
+ /**
224
+ * How `value` changes the attribute.
225
+ */
226
+ operator: EffectOperator;
227
+ /**
228
+ * The source attribute's value, as pass 3 used it.
229
+ */
230
+ value: number;
231
+ /**
232
+ * A penalised stack is split into one entry per item, as each gets its own penalty.
233
+ */
234
+ quantity: number;
235
+ /**
236
+ * The stacking penalty factor applied; `None` when not penalised.
237
+ */
238
+ penalty: number | undefined;
239
+ /**
240
+ * False when the source's state is too low for the effect.
241
+ */
242
+ applied: boolean;
243
+ }
244
+
245
+ /**
246
+ * One rule the fit breaks, and what breaks it.
247
+ */
248
+ export interface Violation {
249
+ /**
250
+ * What the rule is about.
251
+ */
252
+ target: Target;
253
+ /**
254
+ * The rule, and the values that failed it.
255
+ */
256
+ rule: Rule;
257
+ }
258
+
259
+ /**
260
+ * The calculated attributes of the ship, its mode, the character, or one item.
261
+ */
262
+ export interface ItemResult {
263
+ /**
264
+ * Every attribute, by attribute id.
265
+ */
266
+ attributes: Map<number, AttributeValue>;
267
+ /**
268
+ * The state actually reached, which may be below what was requested.
269
+ */
270
+ state: State;
271
+ /**
272
+ * The highest state the item can reach.
273
+ */
274
+ max_state: State;
275
+ /**
276
+ * The charge loaded in the module, if any.
277
+ */
278
+ charge: ItemResult | undefined;
279
+ }
280
+
281
+ /**
282
+ * The character flying the ship.
283
+ */
284
+ export interface Character {
285
+ /**
286
+ * The level of each skill, by type id. A skill that is not listed is not
287
+ * trained, and gives no bonus.
288
+ */
289
+ skills?: Map<number, number> | Record<number, number>;
290
+ /**
291
+ * -10.0 to 5.0. Only a few ships have a bonus that scales with it.
292
+ */
293
+ security_status?: number;
294
+ }
295
+
296
+ /**
297
+ * The external buffs and effects that can be applied to another ship.
298
+ *
299
+ * A calculation reports what the fit hands out; put that in
300
+ * [`Fit::incoming`](crate::Fit::incoming) of another fit to have it applied.
301
+ */
302
+ export interface Projection {
303
+ /**
304
+ * Buffs, like command burst hands.
305
+ */
306
+ buffs?: ProjectedBuff[];
307
+ /**
308
+ * Effects, like webifiers, remote reps, etc.
309
+ */
310
+ effects?: ProjectedEffect[];
311
+ }
312
+
313
+ /**
314
+ * The result of [`calculate()`](crate::calculate).
315
+ */
316
+ export interface Calculation {
317
+ /**
318
+ * The ship.
319
+ */
320
+ ship: ItemResult;
321
+ /**
322
+ * The active mode, if the ship has one.
323
+ */
324
+ mode?: ItemResult;
325
+ /**
326
+ * Index-parallel to `Fit::items`: same length, same order.
327
+ */
328
+ items: ItemResult[];
329
+ /**
330
+ * The character.
331
+ */
332
+ character: ItemResult;
333
+ /**
334
+ * The buffs that landed, ordered by id: those of `Fit::incoming`, plus
335
+ * the ones the fit's own bursts hand out. What is missing lost to another
336
+ * source of the same buff, or the SDE has no such buff.
337
+ */
338
+ buffs?: ProjectedBuff[];
339
+ /**
340
+ * All outgoing projections (effects and buffs).
341
+ */
342
+ outgoing?: Projection;
343
+ }
344
+
345
+ /**
346
+ * The security of a solar system.
347
+ */
348
+ export type Security = "high_sec" | "low_sec" | "null_sec" | "wormhole";
349
+
350
+ /**
351
+ * The ship of a fit.
352
+ */
353
+ export interface Ship {
354
+ /**
355
+ * The type id of the ship.
356
+ */
357
+ type_id: number;
358
+ /**
359
+ * The type id of the active mode, for ships that have modes.
360
+ */
361
+ mode?: number;
362
+ }
363
+
364
+ /**
365
+ * The state of an item, lowest first.
366
+ */
367
+ export type State = "offline" | "online" | "active" | "overload";
368
+
369
+ /**
370
+ * What [`calculate()`] reports on top of the values.
371
+ */
372
+ export interface Options {
373
+ /**
374
+ * Report per attribute the modifiers its value was calculated from.
375
+ */
376
+ sources?: boolean;
377
+ }
378
+
379
+ /**
380
+ * What a Reactive Armor Hardener shifts its resistances towards.
381
+ *
382
+ * EVE shows it as a plain 15/15/15/15 hardener, as the client has no damage
383
+ * to shift it against. `DoNotAdapt` reports the same, and is the default.
384
+ */
385
+ export type ReactiveArmor = "do_not_adapt" | "damage_profile" | { profile: DamageProfile };
386
+
387
+ /**
388
+ * What a [`Violation`] is about. `Item` and `Charge` index into `Fit::items`.
389
+ */
390
+ export type Target = { type: "ship" } | { type: "item"; index: number } | { type: "charge"; index: number };
391
+
392
+ /**
393
+ * Where an item is. The number is the position in its rack, starting at 0;
394
+ * for implants and boosters, the slot as EVE numbers it, starting at 1.
395
+ */
396
+ export type Slot = { type: "high"; index: number } | { type: "medium"; index: number } | { type: "low"; index: number } | { type: "rig"; index: number } | { type: "subsystem"; index: number } | { type: "service"; index: number } | { type: "fighter_tube"; index: number } | { type: "fighter_bay" } | { type: "implant"; index: number } | { type: "booster"; index: number } | { type: "drone_bay" } | { type: "cargo" };
397
+
398
+ /**
399
+ * Where the ship is.
400
+ */
401
+ export interface Environment {
402
+ /**
403
+ * The damage the ship is assumed to take, for effective hitpoints.
404
+ */
405
+ damage_profile?: DamageProfile;
406
+ /**
407
+ * The security of the solar system.
408
+ */
409
+ security?: Security;
410
+ /**
411
+ * What a Reactive Armor Hardener shifts its resistances towards.
412
+ */
413
+ reactive_armor?: ReactiveArmor;
414
+ }
415
+
416
+ /**
417
+ * Which state a group limit counts.
418
+ */
419
+ export type GroupLimit = "fitted" | "online" | "active";
420
+
421
+ /**
422
+ * `Item` and `Charge` index into `Fit::items`, `Projected` into
423
+ * `Fit::incoming.effects`. A skill and a buff are not in the result, so they
424
+ * carry their own id.
425
+ */
426
+ export type SourceRef = { type: "ship" } | { type: "mode" } | { type: "character" } | { type: "item"; index: number } | { type: "charge"; index: number } | { type: "skill"; type_id: number } | { type: "projected"; index: number } | { type: "buff"; id: number };
427
+
3
428
 
4
429
  /**
5
430
  * What a beacon in space hands to every fit in there with it. Put the result
6
431
  * in `incoming` of a fit to have it applied.
7
432
  */
8
- export function beacon(type_id: number): any;
433
+ export function beacon(type_id: number): Projection;
9
434
 
10
435
  /**
11
- * `js_options` may be left out; it then uses the defaults.
436
+ * `options` may be left out; it then uses the defaults.
12
437
  */
13
- export function calculate(js_fit: any, js_options: any): any;
438
+ export function calculate(fit: Fit, options?: Options | null): Calculation;
14
439
 
15
440
  export function init(): void;
16
441
 
17
442
  /**
18
443
  * Load a fit from EFT, the text format EVE copies a fit to the clipboard in.
19
444
  */
20
- export function load_eft(eft: string): any;
445
+ export function load_eft(eft: string): Fit;
21
446
 
22
447
  /**
23
448
  * Load `names.dat`, so an EFT written in another language than English also
@@ -31,3 +456,14 @@ export function load_names(bytes: Uint8Array): number;
31
456
  * error, as the first buffer is borrowed for the rest of the session.
32
457
  */
33
458
  export function load_sde(bytes: Uint8Array): number;
459
+
460
+ /**
461
+ * Write a fit as EFT, the text format EVE copies a fit to the clipboard in.
462
+ */
463
+ export function save_eft(fit: Fit): string;
464
+
465
+ /**
466
+ * Report the fitting rules the fit breaks. Calculates the fit itself, as
467
+ * every rule reads the values after skills and modules changed them.
468
+ */
469
+ export function validate(fit: Fit): Violation[];
@@ -5,5 +5,5 @@ import { __wbg_set_wasm } from "./esf_dogma_engine_bg.js";
5
5
  __wbg_set_wasm(wasm);
6
6
  wasm.__wbindgen_start();
7
7
  export {
8
- beacon, calculate, init, load_eft, load_names, load_sde
8
+ beacon, calculate, init, load_eft, load_names, load_sde, save_eft, validate
9
9
  } from "./esf_dogma_engine_bg.js";
@@ -2,7 +2,7 @@
2
2
  * What a beacon in space hands to every fit in there with it. Put the result
3
3
  * in `incoming` of a fit to have it applied.
4
4
  * @param {number} type_id
5
- * @returns {any}
5
+ * @returns {Projection}
6
6
  */
7
7
  export function beacon(type_id) {
8
8
  const ret = wasm.beacon(type_id);
@@ -13,13 +13,13 @@ export function beacon(type_id) {
13
13
  }
14
14
 
15
15
  /**
16
- * `js_options` may be left out; it then uses the defaults.
17
- * @param {any} js_fit
18
- * @param {any} js_options
19
- * @returns {any}
16
+ * `options` may be left out; it then uses the defaults.
17
+ * @param {Fit} fit
18
+ * @param {Options | null} [options]
19
+ * @returns {Calculation}
20
20
  */
21
- export function calculate(js_fit, js_options) {
22
- const ret = wasm.calculate(js_fit, js_options);
21
+ export function calculate(fit, options) {
22
+ const ret = wasm.calculate(fit, isLikeNone(options) ? 0 : addToExternrefTable0(options));
23
23
  if (ret[2]) {
24
24
  throw takeFromExternrefTable0(ret[1]);
25
25
  }
@@ -33,7 +33,7 @@ export function init() {
33
33
  /**
34
34
  * Load a fit from EFT, the text format EVE copies a fit to the clipboard in.
35
35
  * @param {string} eft
36
- * @returns {any}
36
+ * @returns {Fit}
37
37
  */
38
38
  export function load_eft(eft) {
39
39
  const ptr0 = passStringToWasm0(eft, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
@@ -77,6 +77,44 @@ export function load_sde(bytes) {
77
77
  }
78
78
  return ret[0];
79
79
  }
80
+
81
+ /**
82
+ * Write a fit as EFT, the text format EVE copies a fit to the clipboard in.
83
+ * @param {Fit} fit
84
+ * @returns {string}
85
+ */
86
+ export function save_eft(fit) {
87
+ let deferred2_0;
88
+ let deferred2_1;
89
+ try {
90
+ const ret = wasm.save_eft(fit);
91
+ var ptr1 = ret[0];
92
+ var len1 = ret[1];
93
+ if (ret[3]) {
94
+ ptr1 = 0; len1 = 0;
95
+ throw takeFromExternrefTable0(ret[2]);
96
+ }
97
+ deferred2_0 = ptr1;
98
+ deferred2_1 = len1;
99
+ return getStringFromWasm0(ptr1, len1);
100
+ } finally {
101
+ wasm.__wbindgen_free(deferred2_0, deferred2_1, 1);
102
+ }
103
+ }
104
+
105
+ /**
106
+ * Report the fitting rules the fit breaks. Calculates the fit itself, as
107
+ * every rule reads the values after skills and modules changed them.
108
+ * @param {Fit} fit
109
+ * @returns {Violation[]}
110
+ */
111
+ export function validate(fit) {
112
+ const ret = wasm.validate(fit);
113
+ if (ret[2]) {
114
+ throw takeFromExternrefTable0(ret[1]);
115
+ }
116
+ return takeFromExternrefTable0(ret[0]);
117
+ }
80
118
  export function __wbg_Error_67e7344beaa85059(arg0, arg1) {
81
119
  const ret = Error(getStringFromWasm0(arg0, arg1));
82
120
  return ret;
@@ -122,10 +160,6 @@ export function __wbg___wbindgen_is_function_fcda5e3902d732fe(arg0) {
122
160
  const ret = typeof(arg0) === 'function';
123
161
  return ret;
124
162
  }
125
- export function __wbg___wbindgen_is_null_5160b3e381865372(arg0) {
126
- const ret = arg0 === null;
127
- return ret;
128
- }
129
163
  export function __wbg___wbindgen_is_object_edb6b15aa3afe12e(arg0) {
130
164
  const val = arg0;
131
165
  const ret = typeof(val) === 'object' && val !== null;
Binary file
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "EVEShipFit Team <info@eveship.fit>"
6
6
  ],
7
7
  "description": "Library to calculate statistics for EVE Online ship fits",
8
- "version": "11.0.1",
8
+ "version": "11.2.0",
9
9
  "license": "MIT",
10
10
  "repository": {
11
11
  "type": "git",