mana-scribe 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/.c8rc.json +10 -0
- package/.github/workflows/tests.yml +37 -0
- package/LICENSE +7 -0
- package/README.md +79 -0
- package/jasmine.json +8 -0
- package/package.json +35 -0
- package/src/costs/ActivationCost.js +32 -0
- package/src/costs/Cost.js +48 -0
- package/src/costs/ManaCost.js +38 -0
- package/src/customErrors.js +6 -0
- package/src/index.js +4 -0
- package/src/symbols/ColoredManaSymbol.js +20 -0
- package/src/symbols/ColoredPhyrexianManaSymbol.js +20 -0
- package/src/symbols/ColorlessManaSymbol.js +20 -0
- package/src/symbols/ColorlessPhyrexianManaSymbol.js +12 -0
- package/src/symbols/EnergySymbol.js +12 -0
- package/src/symbols/FiveColorHybridManaSymbol.js +12 -0
- package/src/symbols/FourColorHybridManaSymbol.js +12 -0
- package/src/symbols/GenericHybridManaSymbol.js +20 -0
- package/src/symbols/GenericManaSymbol.js +16 -0
- package/src/symbols/HalfColoredManaSymbol.js +21 -0
- package/src/symbols/HybridManaSymbol.js +21 -0
- package/src/symbols/InfiniteManaSymbol.js +16 -0
- package/src/symbols/NonManaSymbol.js +11 -0
- package/src/symbols/SnowManaSymbol.js +20 -0
- package/src/symbols/Symbol.js +44 -0
- package/src/symbols/TapSymbol.js +12 -0
- package/src/symbols/ThreeColorHybridManaSymbol.js +12 -0
- package/src/symbols/TwoColorHybridManaSymbol.js +12 -0
- package/src/symbols/UntapSymbol.js +12 -0
- package/src/symbols/VariableManaSymbol.js +16 -0
- package/tests/costs/ActivationCost.test.js +65 -0
- package/tests/costs/Cost.test.js +27 -0
- package/tests/costs/ManaCost.test.js +124 -0
- package/tests/realWorld.test.js +80 -0
- package/tests/symbols/ColoredManaSymbol.js +62 -0
- package/tests/symbols/ColoredPhyrexianManaSymbol.test.js +69 -0
- package/tests/symbols/ColorlessManaSymbol.test.js +56 -0
- package/tests/symbols/ColorlessPhyrexianManaSymbol.test.js +61 -0
- package/tests/symbols/EnergySymbol.test.js +75 -0
- package/tests/symbols/FiveColorHybridManaSymbol.test.js +70 -0
- package/tests/symbols/FourColorHybridManaSymbol.test.js +70 -0
- package/tests/symbols/GenericHybridManaSymbol.test.js +77 -0
- package/tests/symbols/GenericManaSymbol.test.js +68 -0
- package/tests/symbols/HalfColoredManaSymbol.test.js +80 -0
- package/tests/symbols/InfiniteManaSymbol.test.js +70 -0
- package/tests/symbols/SnowManaSymbol.test.js +70 -0
- package/tests/symbols/Symbol.test.js +41 -0
- package/tests/symbols/TapSymbol.test.js +74 -0
- package/tests/symbols/ThreeColorHybridManaSymbol.test.js +68 -0
- package/tests/symbols/TwoColorHybridManaSymbol.test.js +68 -0
- package/tests/symbols/UntapSymbol.test.js +74 -0
- package/tests/symbols/VariableManaSymbol.test.js +72 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import ThreeColorHybridManaSymbol from '../../src/symbols/ThreeColorHybridManaSymbol.js';
|
|
2
|
+
|
|
3
|
+
describe('ThreeColorHybridManaSymbol', () => {
|
|
4
|
+
describe('fromString()', () => {
|
|
5
|
+
it('creates a symbol from three-color hybrid (braced and shortform)', () => {
|
|
6
|
+
const sym1 = ThreeColorHybridManaSymbol.fromString('{W/U/B}');
|
|
7
|
+
expect(sym1.raw).toBe('W/U/B');
|
|
8
|
+
expect(sym1.colors.sort()).toEqual(['B','U','W']);
|
|
9
|
+
|
|
10
|
+
const sym2 = ThreeColorHybridManaSymbol.fromString('R/G/U');
|
|
11
|
+
expect(sym2.raw).toBe('R/G/U');
|
|
12
|
+
expect(sym2.colors.sort()).toEqual(['G','R','U']);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it('is case insensitive', () => {
|
|
16
|
+
const sym = ThreeColorHybridManaSymbol.fromString('{w/u/g}');
|
|
17
|
+
expect(sym.raw).toBe('W/U/G');
|
|
18
|
+
expect(sym.colors.sort()).toEqual(['G','U','W']);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('throws for invalid input', () => {
|
|
22
|
+
// fewer than 3 colors
|
|
23
|
+
expect(() => ThreeColorHybridManaSymbol.fromString('W/U')).toThrow();
|
|
24
|
+
// duplicates
|
|
25
|
+
expect(() => ThreeColorHybridManaSymbol.fromString('W/U/W')).toThrow();
|
|
26
|
+
// invalid char
|
|
27
|
+
expect(() => ThreeColorHybridManaSymbol.fromString('W/U/C')).toThrow();
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
describe('properties', () => {
|
|
32
|
+
it('has type threeColorHybridMana', () => {
|
|
33
|
+
const sym = ThreeColorHybridManaSymbol.fromString('W/U/B');
|
|
34
|
+
expect(sym.type).toBe('threeColorHybridMana');
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('cmcValue is always 1', () => {
|
|
38
|
+
const sym = ThreeColorHybridManaSymbol.fromString('{W/U/B}');
|
|
39
|
+
expect(sym.cmcValue()).toBe(1);
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
describe('inherited methods', () => {
|
|
44
|
+
it('apply() pushes to array', () => {
|
|
45
|
+
const arr = [];
|
|
46
|
+
const sym = ThreeColorHybridManaSymbol.fromString('W/U/B');
|
|
47
|
+
sym.apply(arr);
|
|
48
|
+
expect(arr[0]).toBe(sym);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('toString() outputs correctly', () => {
|
|
52
|
+
const sym = ThreeColorHybridManaSymbol.fromString('{W/U/B}');
|
|
53
|
+
expect(sym.toString(false)).toBe('W/U/B');
|
|
54
|
+
expect(sym.toString(true)).toBe('{W/U/B}');
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
describe('roundtrip', () => {
|
|
59
|
+
it('parses and serializes symmetrically', () => {
|
|
60
|
+
const input = '{W/U/B}';
|
|
61
|
+
const sym1 = ThreeColorHybridManaSymbol.fromString(input);
|
|
62
|
+
const str = sym1.toString(true);
|
|
63
|
+
const sym2 = ThreeColorHybridManaSymbol.fromString(str);
|
|
64
|
+
expect(sym2.raw).toBe('W/U/B');
|
|
65
|
+
expect(sym2.colors.sort()).toEqual(['B','U','W']);
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
});
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import TwoColorHybridManaSymbol from '../../src/symbols/TwoColorHybridManaSymbol.js';
|
|
2
|
+
|
|
3
|
+
describe('TwoColorHybridManaSymbol', () => {
|
|
4
|
+
describe('fromString()', () => {
|
|
5
|
+
it('creates a symbol from two-color hybrid (braced and shortform)', () => {
|
|
6
|
+
const sym1 = TwoColorHybridManaSymbol.fromString('{W/U}');
|
|
7
|
+
expect(sym1.raw).toBe('W/U');
|
|
8
|
+
expect(sym1.colors.sort()).toEqual(['U','W']);
|
|
9
|
+
|
|
10
|
+
const sym2 = TwoColorHybridManaSymbol.fromString('R/G');
|
|
11
|
+
expect(sym2.raw).toBe('R/G');
|
|
12
|
+
expect(sym2.colors.sort()).toEqual(['G','R']);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it('is case insensitive', () => {
|
|
16
|
+
const sym = TwoColorHybridManaSymbol.fromString('{b/r}');
|
|
17
|
+
expect(sym.raw).toBe('B/R');
|
|
18
|
+
expect(sym.colors.sort()).toEqual(['B','R']);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('throws for invalid input', () => {
|
|
22
|
+
// single color
|
|
23
|
+
expect(() => TwoColorHybridManaSymbol.fromString('W')).toThrow();
|
|
24
|
+
// duplicates
|
|
25
|
+
expect(() => TwoColorHybridManaSymbol.fromString('W/W')).toThrow();
|
|
26
|
+
// invalid char
|
|
27
|
+
expect(() => TwoColorHybridManaSymbol.fromString('W/C')).toThrow();
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
describe('properties', () => {
|
|
32
|
+
it('has type twoColorHybridMana', () => {
|
|
33
|
+
const sym = TwoColorHybridManaSymbol.fromString('W/U');
|
|
34
|
+
expect(sym.type).toBe('twoColorHybridMana');
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('cmcValue is always 1', () => {
|
|
38
|
+
const sym = TwoColorHybridManaSymbol.fromString('{R/G}');
|
|
39
|
+
expect(sym.cmcValue()).toBe(1);
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
describe('inherited methods', () => {
|
|
44
|
+
it('apply() pushes to array', () => {
|
|
45
|
+
const arr = [];
|
|
46
|
+
const sym = TwoColorHybridManaSymbol.fromString('W/U');
|
|
47
|
+
sym.apply(arr);
|
|
48
|
+
expect(arr[0]).toBe(sym);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('toString() outputs correctly', () => {
|
|
52
|
+
const sym = TwoColorHybridManaSymbol.fromString('{U/B}');
|
|
53
|
+
expect(sym.toString(false)).toBe('U/B');
|
|
54
|
+
expect(sym.toString(true)).toBe('{U/B}');
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
describe('roundtrip', () => {
|
|
59
|
+
it('parses and serializes symmetrically', () => {
|
|
60
|
+
const input = '{G/R}';
|
|
61
|
+
const sym1 = TwoColorHybridManaSymbol.fromString(input);
|
|
62
|
+
const str = sym1.toString(true);
|
|
63
|
+
const sym2 = TwoColorHybridManaSymbol.fromString(str);
|
|
64
|
+
expect(sym2.raw).toBe('G/R');
|
|
65
|
+
expect(sym2.colors.sort()).toEqual(['G','R']);
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
});
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import UntapSymbol from '../../src/symbols/UntapSymbol.js';
|
|
2
|
+
|
|
3
|
+
describe('UntapSymbol', () => {
|
|
4
|
+
describe('fromString()', () => {
|
|
5
|
+
it('creates a symbol from Q (shortform and braced)', () => {
|
|
6
|
+
const sym1 = UntapSymbol.fromString('Q');
|
|
7
|
+
expect(sym1.raw).toBe('Q');
|
|
8
|
+
expect(sym1.type).toBe('untap');
|
|
9
|
+
expect(sym1.cmcValue()).toBe(0);
|
|
10
|
+
expect(sym1.colors).toEqual([]);
|
|
11
|
+
|
|
12
|
+
const sym2 = UntapSymbol.fromString('{Q}');
|
|
13
|
+
expect(sym2.raw).toBe('Q');
|
|
14
|
+
expect(sym2.type).toBe('untap');
|
|
15
|
+
expect(sym2.cmcValue()).toBe(0);
|
|
16
|
+
expect(sym2.colors).toEqual([]);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('is case insensitive', () => {
|
|
20
|
+
const sym = UntapSymbol.fromString('{q}');
|
|
21
|
+
expect(sym.raw).toBe('Q');
|
|
22
|
+
expect(sym.type).toBe('untap');
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('throws for invalid input', () => {
|
|
26
|
+
expect(() => UntapSymbol.fromString('T')).toThrow(); // Tap, not Untap
|
|
27
|
+
expect(() => UntapSymbol.fromString('{W}')).toThrow();
|
|
28
|
+
expect(() => UntapSymbol.fromString('')).toThrow();
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
describe('properties', () => {
|
|
33
|
+
it('has type untap', () => {
|
|
34
|
+
const sym = UntapSymbol.fromString('Q');
|
|
35
|
+
expect(sym.type).toBe('untap');
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('cmcValue is always 0', () => {
|
|
39
|
+
const sym = UntapSymbol.fromString('{Q}');
|
|
40
|
+
expect(sym.cmcValue()).toBe(0);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('colors is always empty', () => {
|
|
44
|
+
const sym = UntapSymbol.fromString('Q');
|
|
45
|
+
expect(sym.colors).toEqual([]);
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
describe('inherited methods', () => {
|
|
50
|
+
it('apply() pushes to array', () => {
|
|
51
|
+
const arr = [];
|
|
52
|
+
const sym = UntapSymbol.fromString('Q');
|
|
53
|
+
sym.apply(arr);
|
|
54
|
+
expect(arr[0]).toBe(sym);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('toString() outputs correctly', () => {
|
|
58
|
+
const sym = UntapSymbol.fromString('{Q}');
|
|
59
|
+
expect(sym.toString(false)).toBe('Q');
|
|
60
|
+
expect(sym.toString(true)).toBe('{Q}');
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
describe('roundtrip', () => {
|
|
65
|
+
it('parses and serializes symmetrically', () => {
|
|
66
|
+
const input = '{Q}';
|
|
67
|
+
const sym1 = UntapSymbol.fromString(input);
|
|
68
|
+
const str = sym1.toString(true);
|
|
69
|
+
const sym2 = UntapSymbol.fromString(str);
|
|
70
|
+
expect(sym2.raw).toBe('Q');
|
|
71
|
+
expect(sym2.type).toBe('untap');
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
});
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import VariableManaSymbol from '../../src/symbols/VariableManaSymbol.js';
|
|
2
|
+
|
|
3
|
+
describe('VariableManaSymbol', () => {
|
|
4
|
+
describe('fromString()', () => {
|
|
5
|
+
it('creates a symbol from variable (shortform and braced)', () => {
|
|
6
|
+
for (const v of ['X','Y','Z']) {
|
|
7
|
+
const sym1 = VariableManaSymbol.fromString(v);
|
|
8
|
+
expect(sym1.raw).toBe(v);
|
|
9
|
+
expect(sym1.cmcValue()).toBe(0);
|
|
10
|
+
|
|
11
|
+
const sym2 = VariableManaSymbol.fromString(`{${v}}`);
|
|
12
|
+
expect(sym2.raw).toBe(v);
|
|
13
|
+
expect(sym2.cmcValue()).toBe(0);
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it('is case insensitive', () => {
|
|
18
|
+
const sym = VariableManaSymbol.fromString('{x}');
|
|
19
|
+
expect(sym.raw).toBe('X');
|
|
20
|
+
expect(sym.cmcValue()).toBe(0);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('throws for invalid input', () => {
|
|
24
|
+
expect(() => VariableManaSymbol.fromString('W')).toThrow();
|
|
25
|
+
expect(() => VariableManaSymbol.fromString('1')).toThrow();
|
|
26
|
+
expect(() => VariableManaSymbol.fromString('')).toThrow();
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
describe('properties', () => {
|
|
31
|
+
it('has type variable', () => {
|
|
32
|
+
const sym = VariableManaSymbol.fromString('X');
|
|
33
|
+
expect(sym.type).toBe('variableMana');
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('cmcValue is always 0', () => {
|
|
37
|
+
const sym = VariableManaSymbol.fromString('{Y}');
|
|
38
|
+
expect(sym.cmcValue()).toBe(0);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('colors is always empty', () => {
|
|
42
|
+
const sym = VariableManaSymbol.fromString('Z');
|
|
43
|
+
expect(sym.colors).toEqual([]);
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
describe('inherited methods', () => {
|
|
48
|
+
it('apply() pushes to array', () => {
|
|
49
|
+
const arr = [];
|
|
50
|
+
const sym = VariableManaSymbol.fromString('X');
|
|
51
|
+
sym.apply(arr);
|
|
52
|
+
expect(arr[0]).toBe(sym);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('toString() outputs correctly', () => {
|
|
56
|
+
const sym = VariableManaSymbol.fromString('{Y}');
|
|
57
|
+
expect(sym.toString(false)).toBe('Y');
|
|
58
|
+
expect(sym.toString(true)).toBe('{Y}');
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
describe('roundtrip', () => {
|
|
63
|
+
it('parses and serializes symmetrically', () => {
|
|
64
|
+
const input = '{Z}';
|
|
65
|
+
const sym1 = VariableManaSymbol.fromString(input);
|
|
66
|
+
const str = sym1.toString(true);
|
|
67
|
+
const sym2 = VariableManaSymbol.fromString(str);
|
|
68
|
+
expect(sym2.raw).toBe('Z');
|
|
69
|
+
expect(sym2.cmcValue()).toBe(0);
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
});
|