chordsheetjs 5.3.0 → 6.1.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.
@@ -0,0 +1,5 @@
1
+ #!/bin/sh
2
+ . "$(dirname "$0")/_/husky.sh"
3
+
4
+ yarn readme
5
+ git add README.md
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # ChordSheetJS [![Build Status](https://travis-ci.org/martijnversluis/ChordSheetJS.svg?branch=master)](https://travis-ci.org/martijnversluis/ChordSheetJS) [![npm version](https://badge.fury.io/js/chordsheetjs.svg)](https://badge.fury.io/js/chordsheetjs) [![Code Climate](https://codeclimate.com/github/martijnversluis/ChordSheetJS/badges/gpa.svg)](https://codeclimate.com/github/martijnversluis/ChordSheetJS)
1
+ # ChordChartJS [![Code Climate](https://codeclimate.com/github/PraiseCharts/ChordChartJS/badges/gpa.svg)](https://codeclimate.com/github/PraiseCharts/ChordChartJS)
2
2
 
3
3
  A JavaScript library for parsing and formatting chord sheets
4
4
 
@@ -466,6 +466,12 @@ Inherits from <a href="#ChordSheetParser">ChordSheetParser</a></p>
466
466
  <dt><a href="#TITLE">TITLE</a> : <code>string</code></dt>
467
467
  <dd><p>Title meta directive. See <a href="https://www.chordpro.org/chordpro/directives-title/">https://www.chordpro.org/chordpro/directives-title/</a></p>
468
468
  </dd>
469
+ <dt><a href="#TRANSPOSE">TRANSPOSE</a> : <code>string</code></dt>
470
+ <dd><p>Transpose meta directive. See: <a href="https://www.chordpro.org/chordpro/directives-transpose/">https://www.chordpro.org/chordpro/directives-transpose/</a></p>
471
+ </dd>
472
+ <dt><a href="#NEW_KEY">NEW_KEY</a> : <code>string</code></dt>
473
+ <dd><p>New Key meta directive. See: <a href="https://github.com/PraiseCharts/ChordChartJS/issues/53">https://github.com/PraiseCharts/ChordChartJS/issues/53</a></p>
474
+ </dd>
469
475
  <dt><a href="#YEAR">YEAR</a> : <code>string</code></dt>
470
476
  <dd><p>Year meta directive. See <a href="https://www.chordpro.org/chordpro/directives-year/">https://www.chordpro.org/chordpro/directives-year/</a></p>
471
477
  </dd>
@@ -753,6 +759,8 @@ Represents a song in a chord sheet. Currently a chord sheet can only have one so
753
759
  * [.bodyParagraphs](#Song+bodyParagraphs) ⇒ [<code>Array.&lt;Paragraph&gt;</code>](#Paragraph)
754
760
  * ~~[.metaData](#Song+metaData) ⇒~~
755
761
  * [.clone()](#Song+clone) ⇒ [<code>Song</code>](#Song)
762
+ * [.setCapo(capo)](#Song+setCapo) ⇒ [<code>Song</code>](#Song)
763
+ * [.setKey(key)](#Song+setKey) ⇒ [<code>Song</code>](#Song)
756
764
 
757
765
  <a name="new_Song_new"></a>
758
766
 
@@ -815,6 +823,35 @@ Returns a deep clone of the song
815
823
 
816
824
  **Kind**: instance method of [<code>Song</code>](#Song)
817
825
  **Returns**: [<code>Song</code>](#Song) - The cloned song
826
+ <a name="Song+setCapo"></a>
827
+
828
+ ### song.setCapo(capo) ⇒ [<code>Song</code>](#Song)
829
+ Returns a copy of the song with the capo value set to the specified capo. It changes:
830
+ - the value for `capo` in the `metadata` set
831
+ - any existing `capo` directive)
832
+
833
+ **Kind**: instance method of [<code>Song</code>](#Song)
834
+ **Returns**: [<code>Song</code>](#Song) - The changed song
835
+
836
+ | Param | Type | Description |
837
+ | --- | --- | --- |
838
+ | capo | <code>number</code> \| <code>null</code> | the capo. Passing `null` will: - remove the current key from `metadata` - remove any `capo` directive |
839
+
840
+ <a name="Song+setKey"></a>
841
+
842
+ ### song.setKey(key) ⇒ [<code>Song</code>](#Song)
843
+ Returns a copy of the song with the key set to the specified key. It changes:
844
+ - the value for `key` in the `metadata` set
845
+ - any existing `key` directive
846
+ - all chords, those are transposed according to the distance between the current and the new key
847
+
848
+ **Kind**: instance method of [<code>Song</code>](#Song)
849
+ **Returns**: [<code>Song</code>](#Song) - The changed song
850
+
851
+ | Param | Type | Description |
852
+ | --- | --- | --- |
853
+ | key | <code>string</code> | The new key. |
854
+
818
855
  <a name="Tag"></a>
819
856
 
820
857
  ## Tag
@@ -1176,8 +1213,11 @@ Represents a Chord, consisting of a root, suffix (quality) and bass
1176
1213
  * [.toChordSymbolString(key)](#Chord+toChordSymbolString) ⇒ <code>string</code>
1177
1214
  * [.isChordSymbol()](#Chord+isChordSymbol) ⇒ <code>boolean</code>
1178
1215
  * [.toNumeric(key)](#Chord+toNumeric) ⇒ [<code>Chord</code>](#Chord)
1216
+ * [.toNumeral(key)](#Chord+toNumeral) ⇒ [<code>Chord</code>](#Chord)
1217
+ * [.toNumeralString(key)](#Chord+toNumeralString) ⇒ <code>string</code>
1179
1218
  * [.isNumeric()](#Chord+isNumeric) ⇒ <code>boolean</code>
1180
1219
  * [.toNumericString(key)](#Chord+toNumericString) ⇒ <code>string</code>
1220
+ * [.isNumeral()](#Chord+isNumeral) ⇒ <code>boolean</code>
1181
1221
  * [.toString()](#Chord+toString) ⇒ <code>string</code>
1182
1222
  * [.normalize()](#Chord+normalize) ⇒ [<code>Chord</code>](#Chord)
1183
1223
  * [.useModifier(newModifier)](#Chord+useModifier) ⇒ [<code>Chord</code>](#Chord)
@@ -1231,7 +1271,7 @@ Determines whether the chord is a chord symbol
1231
1271
  <a name="Chord+toNumeric"></a>
1232
1272
 
1233
1273
  ### chord.toNumeric(key) ⇒ [<code>Chord</code>](#Chord)
1234
- Converts the chord to a numeric chord, using the supplied kye as a reference.
1274
+ Converts the chord to a numeric chord, using the supplied key as a reference.
1235
1275
  For example, a chord symbol A# with reference key E will return the numeric chord #4.
1236
1276
 
1237
1277
  **Kind**: instance method of [<code>Chord</code>](#Chord)
@@ -1241,6 +1281,33 @@ For example, a chord symbol A# with reference key E will return the numeric chor
1241
1281
  | --- | --- | --- |
1242
1282
  | key | <code>Key</code> \| <code>string</code> | the reference key |
1243
1283
 
1284
+ <a name="Chord+toNumeral"></a>
1285
+
1286
+ ### chord.toNumeral(key) ⇒ [<code>Chord</code>](#Chord)
1287
+ Converts the chord to a numeral chord, using the supplied key as a reference.
1288
+ For example, a chord symbol A# with reference key E will return the numeral chord #IV.
1289
+
1290
+ **Kind**: instance method of [<code>Chord</code>](#Chord)
1291
+ **Returns**: [<code>Chord</code>](#Chord) - the numeral chord
1292
+
1293
+ | Param | Type | Default | Description |
1294
+ | --- | --- | --- | --- |
1295
+ | key | <code>Key</code> \| <code>string</code> \| <code>null</code> | <code></code> | the reference key. The key is required when converting a chord symbol |
1296
+
1297
+ <a name="Chord+toNumeralString"></a>
1298
+
1299
+ ### chord.toNumeralString(key) ⇒ <code>string</code>
1300
+ Converts the chord to a numeral chord string, using the supplied kye as a reference.
1301
+ For example, a chord symbol A# with reference key E will return the numeral chord #4.
1302
+
1303
+ **Kind**: instance method of [<code>Chord</code>](#Chord)
1304
+ **Returns**: <code>string</code> - the numeral chord string
1305
+ **See**: {toNumeral}
1306
+
1307
+ | Param | Type | Description |
1308
+ | --- | --- | --- |
1309
+ | key | <code>Key</code> \| <code>string</code> | the reference key |
1310
+
1244
1311
  <a name="Chord+isNumeric"></a>
1245
1312
 
1246
1313
  ### chord.isNumeric() ⇒ <code>boolean</code>
@@ -1261,6 +1328,12 @@ For example, a chord symbol A# with reference key E will return the numeric chor
1261
1328
  | --- | --- | --- |
1262
1329
  | key | <code>Key</code> \| <code>string</code> | the reference key |
1263
1330
 
1331
+ <a name="Chord+isNumeral"></a>
1332
+
1333
+ ### chord.isNumeral() ⇒ <code>boolean</code>
1334
+ Determines whether the chord is a numeral
1335
+
1336
+ **Kind**: instance method of [<code>Chord</code>](#Chord)
1264
1337
  <a name="Chord+toString"></a>
1265
1338
 
1266
1339
  ### chord.toString() ⇒ <code>string</code>
@@ -1271,7 +1344,7 @@ Converts the chord to a string, eg `Esus4/G#` or `1sus4/#3`
1271
1344
  <a name="Chord+normalize"></a>
1272
1345
 
1273
1346
  ### chord.normalize() ⇒ [<code>Chord</code>](#Chord)
1274
- Normalizes the chord:
1347
+ Normalizes the chord root and bass notes:
1275
1348
  - Fb becomes E
1276
1349
  - Cb becomes B
1277
1350
  - B# becomes C
@@ -1281,7 +1354,8 @@ Normalizes the chord:
1281
1354
  - 7# becomes 1
1282
1355
  - 3# becomes 4
1283
1356
 
1284
- If the chord is already normalized, this will return a copy.
1357
+ Besides that it normalizes the suffix. For example, `sus2` becomes `2`, `sus4` becomes `sus`.
1358
+ All suffix normalizations can be found in `src/normalize_mappings/suffix-mapping.txt`.
1285
1359
 
1286
1360
  **Kind**: instance method of [<code>Chord</code>](#Chord)
1287
1361
  **Returns**: [<code>Chord</code>](#Chord) - the normalized chord
@@ -1484,6 +1558,18 @@ Time meta directive. See https://www.chordpro.org/chordpro/directives-time/
1484
1558
  ## TITLE : <code>string</code>
1485
1559
  Title meta directive. See https://www.chordpro.org/chordpro/directives-title/
1486
1560
 
1561
+ **Kind**: global constant
1562
+ <a name="TRANSPOSE"></a>
1563
+
1564
+ ## TRANSPOSE : <code>string</code>
1565
+ Transpose meta directive. See: https://www.chordpro.org/chordpro/directives-transpose/
1566
+
1567
+ **Kind**: global constant
1568
+ <a name="NEW_KEY"></a>
1569
+
1570
+ ## NEW\_KEY : <code>string</code>
1571
+ New Key meta directive. See: https://github.com/PraiseCharts/ChordChartJS/issues/53
1572
+
1487
1573
  **Kind**: global constant
1488
1574
  <a name="YEAR"></a>
1489
1575
 
package/lib/chord.js CHANGED
@@ -12,6 +12,8 @@ var _utilities = require("./utilities");
12
12
 
13
13
  var _key = _interopRequireDefault(require("./key"));
14
14
 
15
+ var _suffixNormalizeMapping = _interopRequireDefault(require("./normalize_mappings/suffix-normalize-mapping"));
16
+
15
17
  var _constants = require("./constants");
16
18
 
17
19
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
@@ -36,12 +38,6 @@ function _checkPrivateRedeclaration(obj, privateCollection) { if (privateCollect
36
38
 
37
39
  function _classPrivateMethodGet(receiver, privateSet, fn) { if (!privateSet.has(receiver)) { throw new TypeError("attempted to get private field on non-instance"); } return fn; }
38
40
 
39
- function _classPrivateFieldGet(receiver, privateMap) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "get"); return _classApplyDescriptorGet(receiver, descriptor); }
40
-
41
- function _classExtractFieldDescriptor(receiver, privateMap, action) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to " + action + " private field on non-instance"); } return privateMap.get(receiver); }
42
-
43
- function _classApplyDescriptorGet(receiver, descriptor) { if (descriptor.get) { return descriptor.get.call(receiver); } return descriptor.value; }
44
-
45
41
  function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
46
42
 
47
43
  function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
@@ -60,23 +56,12 @@ function _inherits(subClass, superClass) { if (typeof superClass !== "function"
60
56
 
61
57
  function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
62
58
 
63
- var MAJOR_SCALE = [null, 'M', 'm', 'm', 'M', 'M', 'm', 'dim'];
64
-
65
59
  function normalizeSuffix(suffix) {
66
- if (suffix === 'M') {
67
- return '';
60
+ if (_suffixNormalizeMapping["default"][suffix] === '[blank]') {
61
+ return null;
68
62
  }
69
63
 
70
- return suffix;
71
- }
72
-
73
- function chordSuffix(noteNumber, suffix) {
74
- if ((0, _utilities.isEmptyString)(suffix)) {
75
- var defaultSuffix = MAJOR_SCALE[noteNumber];
76
- return normalizeSuffix(defaultSuffix);
77
- }
78
-
79
- return normalizeSuffix(suffix);
64
+ return _suffixNormalizeMapping["default"][suffix] || suffix;
80
65
  }
81
66
 
82
67
  var chordRegex = /*#__PURE__*/_wrapRegExp(/^([A-G])(#|b)?((?:(?![\t-\r \/\xA0\u1680\u2000-\u200A\u2028\u2029\u202F\u205F\u3000\uFEFF])[\s\S])*)(\/([A-G])(#|b)?)?$/i, {
@@ -143,15 +128,24 @@ var Chord = /*#__PURE__*/function () {
143
128
  set: void 0
144
129
  });
145
130
 
131
+ this.suffix = (0, _utilities.presence)(suffix);
146
132
  this.root = root || new _key["default"]({
147
133
  note: base,
148
- modifier: modifier
134
+ modifier: modifier,
135
+ minor: suffix === 'm'
149
136
  });
150
- this.suffix = (0, _utilities.presence)(suffix);
151
- this.bass = bass || (bassBase ? new _key["default"]({
152
- note: bassBase,
153
- modifier: bassModifier
154
- }) : null);
137
+
138
+ if (bass) {
139
+ this.bass = bass;
140
+ } else if (bassBase) {
141
+ this.bass = new _key["default"]({
142
+ note: bassBase,
143
+ modifier: bassModifier,
144
+ minor: suffix === 'm'
145
+ });
146
+ } else {
147
+ this.bass = null;
148
+ }
155
149
  }
156
150
 
157
151
  _createClass(Chord, [{
@@ -183,10 +177,11 @@ var Chord = /*#__PURE__*/function () {
183
177
 
184
178
  var keyObj = _key["default"].wrap(key);
185
179
 
180
+ var rootKey = this.root.toChordSymbol(keyObj).normalizeEnharmonics(keyObj);
186
181
  var chordSymbolChord = new Chord({
187
- suffix: chordSuffix(_classPrivateFieldGet(this, _rootNote), this.suffix),
188
- root: this.root.toChordSymbol(keyObj),
189
- bass: (_this$bass = this.bass) === null || _this$bass === void 0 ? void 0 : _this$bass.toChordSymbol(keyObj)
182
+ suffix: normalizeSuffix(this.suffix),
183
+ root: rootKey,
184
+ bass: (_this$bass = this.bass) === null || _this$bass === void 0 ? void 0 : _this$bass.toChordSymbol(keyObj).normalizeEnharmonics(rootKey)
190
185
  });
191
186
 
192
187
  if (this.root.isMinor()) {
@@ -247,7 +242,7 @@ var Chord = /*#__PURE__*/function () {
247
242
  var keyObj = _key["default"].wrap(key);
248
243
 
249
244
  return new Chord({
250
- suffix: chordSuffix(_classPrivateFieldGet(this, _rootNote), this.suffix),
245
+ suffix: normalizeSuffix(this.suffix),
251
246
  root: this.root.toNumeric(keyObj),
252
247
  bass: (_this$bass3 = this.bass) === null || _this$bass3 === void 0 ? void 0 : _this$bass3.toNumeric(keyObj)
253
248
  });
@@ -282,7 +277,7 @@ var Chord = /*#__PURE__*/function () {
282
277
  var keyObj = _key["default"].wrap(key);
283
278
 
284
279
  return new Chord({
285
- suffix: chordSuffix(_classPrivateFieldGet(this, _rootNote), this.suffix),
280
+ suffix: normalizeSuffix(this.suffix),
286
281
  root: this.root.toNumeral(keyObj),
287
282
  bass: (_this$bass5 = this.bass) === null || _this$bass5 === void 0 ? void 0 : _this$bass5.toNumeral(keyObj)
288
283
  });
@@ -350,7 +345,7 @@ var Chord = /*#__PURE__*/function () {
350
345
  return chordString;
351
346
  }
352
347
  /**
353
- * Normalizes the chord:
348
+ * Normalizes the chord root and bass notes:
354
349
  * - Fb becomes E
355
350
  * - Cb becomes B
356
351
  * - B# becomes C
@@ -360,14 +355,26 @@ var Chord = /*#__PURE__*/function () {
360
355
  * - 7# becomes 1
361
356
  * - 3# becomes 4
362
357
  *
363
- * If the chord is already normalized, this will return a copy.
358
+ * Besides that it normalizes the suffix. For example, `sus2` becomes `2`, `sus4` becomes `sus`.
359
+ * All suffix normalizations can be found in `src/normalize_mappings/suffix-mapping.txt`.
360
+ *
364
361
  * @returns {Chord} the normalized chord
365
362
  */
366
363
 
367
364
  }, {
368
365
  key: "normalize",
369
- value: function normalize() {
370
- return _classPrivateMethodGet(this, _process, _process2).call(this, 'normalize');
366
+ value: function normalize(key) {
367
+ if (!(0, _utilities.presence)(key)) {
368
+ return _classPrivateMethodGet(this, _process, _process2).call(this, 'normalize').set({
369
+ suffix: (0, _utilities.presence)(normalizeSuffix(this.suffix))
370
+ });
371
+ }
372
+
373
+ return this.set({
374
+ root: this.root.normalizeEnharmonics(key),
375
+ suffix: (0, _utilities.presence)(normalizeSuffix(this.suffix)),
376
+ bass: this.bass ? this.bass.normalizeEnharmonics(this.root.toString()) : null
377
+ });
371
378
  }
372
379
  /**
373
380
  * Switches to the specified modifier
@@ -66,6 +66,11 @@ var ChordLyricsPair = /*#__PURE__*/function () {
66
66
  value: function toString() {
67
67
  return "ChordLyricsPair(chords=".concat(this.chords, ", lyrics=").concat(this.lyrics, ")");
68
68
  }
69
+ }, {
70
+ key: "set",
71
+ value: function set(properties) {
72
+ return new this.constructor(properties.chords || this.chords, properties.lyrics || this.lyrics);
73
+ }
69
74
  }]);
70
75
 
71
76
  return ChordLyricsPair;
@@ -15,6 +15,12 @@ var _constants = require("../constants");
15
15
 
16
16
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
17
17
 
18
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
19
+
20
+ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
21
+
22
+ function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
23
+
18
24
  function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
19
25
 
20
26
  function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
@@ -93,9 +99,17 @@ var Line = /*#__PURE__*/function () {
93
99
  }, {
94
100
  key: "clone",
95
101
  value: function clone() {
102
+ return this.mapItems(null);
103
+ }
104
+ }, {
105
+ key: "mapItems",
106
+ value: function mapItems(func) {
96
107
  var clonedLine = new Line();
97
108
  clonedLine.items = this.items.map(function (item) {
98
- return item.clone();
109
+ var clonedItem = item.clone();
110
+ return func ? func(clonedItem) : clonedItem;
111
+ }).filter(function (item) {
112
+ return item;
99
113
  });
100
114
  clonedLine.type = this.type;
101
115
  return clonedLine;
@@ -176,6 +190,14 @@ var Line = /*#__PURE__*/function () {
176
190
  this.items.push(comment);
177
191
  return comment;
178
192
  }
193
+ }, {
194
+ key: "set",
195
+ value: function set(properties) {
196
+ return new this.constructor(_objectSpread({
197
+ type: this.type,
198
+ items: this.items
199
+ }, properties));
200
+ }
179
201
  }]);
180
202
 
181
203
  return Line;
@@ -74,6 +74,11 @@ var Metadata = /*#__PURE__*/function () {
74
74
  }
75
75
 
76
76
  _createClass(Metadata, [{
77
+ key: "contains",
78
+ value: function contains(key) {
79
+ return key in this;
80
+ }
81
+ }, {
77
82
  key: "add",
78
83
  value: function add(key, value) {
79
84
  if ((0, _tag.isReadonlyTag)(key)) {
@@ -98,6 +103,15 @@ var Metadata = /*#__PURE__*/function () {
98
103
 
99
104
  this[key] = [currentValue, value];
100
105
  }
106
+ }, {
107
+ key: "set",
108
+ value: function set(key, value) {
109
+ if (value) {
110
+ this[key] = value;
111
+ } else {
112
+ delete this[key];
113
+ }
114
+ }
101
115
  /**
102
116
  * Reads a metadata value by key. This method supports simple value lookup, as fetching single array values.
103
117
  *
@@ -11,6 +11,12 @@ var _line = _interopRequireDefault(require("./line"));
11
11
 
12
12
  var _paragraph = _interopRequireDefault(require("./paragraph"));
13
13
 
14
+ var _key = _interopRequireDefault(require("../key"));
15
+
16
+ var _chord = _interopRequireDefault(require("../chord"));
17
+
18
+ var _chord_lyrics_pair = _interopRequireDefault(require("./chord_lyrics_pair"));
19
+
14
20
  var _utilities = require("../utilities");
15
21
 
16
22
  var _metadata = _interopRequireDefault(require("./metadata"));
@@ -45,6 +51,22 @@ function _defineProperties(target, props) { for (var i = 0; i < props.length; i+
45
51
 
46
52
  function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
47
53
 
54
+ function _classPrivateMethodInitSpec(obj, privateSet) { _checkPrivateRedeclaration(obj, privateSet); privateSet.add(obj); }
55
+
56
+ function _checkPrivateRedeclaration(obj, privateCollection) { if (privateCollection.has(obj)) { throw new TypeError("Cannot initialize the same private elements twice on an object"); } }
57
+
58
+ function _classPrivateMethodGet(receiver, privateSet, fn) { if (!privateSet.has(receiver)) { throw new TypeError("attempted to get private field on non-instance"); } return fn; }
59
+
60
+ var _insertDirective = /*#__PURE__*/new WeakSet();
61
+
62
+ var _mapItems = /*#__PURE__*/new WeakSet();
63
+
64
+ var _mapLines = /*#__PURE__*/new WeakSet();
65
+
66
+ var _updateItem = /*#__PURE__*/new WeakSet();
67
+
68
+ var _removeItem = /*#__PURE__*/new WeakSet();
69
+
48
70
  /**
49
71
  * Represents a song in a chord sheet. Currently a chord sheet can only have one song.
50
72
  */
@@ -58,16 +80,24 @@ var Song = /*#__PURE__*/function () {
58
80
 
59
81
  _classCallCheck(this, Song);
60
82
 
83
+ _classPrivateMethodInitSpec(this, _removeItem);
84
+
85
+ _classPrivateMethodInitSpec(this, _updateItem);
86
+
87
+ _classPrivateMethodInitSpec(this, _mapLines);
88
+
89
+ _classPrivateMethodInitSpec(this, _mapItems);
90
+
91
+ _classPrivateMethodInitSpec(this, _insertDirective);
92
+
61
93
  /**
62
94
  * The {@link Line} items of which the song consists
63
- * @member
64
- * @type {Array<Line>}
95
+ * @member {Array<Line>}
65
96
  */
66
97
  this.lines = [];
67
98
  /**
68
99
  * The {@link Paragraph} items of which the song consists
69
- * @member
70
- * @type {Paragraph[]}
100
+ * @member {Paragraph[]}
71
101
  */
72
102
 
73
103
  this.paragraphs = [];
@@ -83,6 +113,7 @@ var Song = /*#__PURE__*/function () {
83
113
  this.warnings = [];
84
114
  this.sectionType = _constants.NONE;
85
115
  this.currentKey = null;
116
+ this.transposeKey = null;
86
117
  }
87
118
 
88
119
  _createClass(Song, [{
@@ -147,11 +178,14 @@ var Song = /*#__PURE__*/function () {
147
178
  }, {
148
179
  key: "addLine",
149
180
  value: function addLine() {
181
+ var _this$transposeKey;
182
+
150
183
  this.ensureParagraph();
151
184
  this.flushLine();
152
185
  this.currentLine = (0, _utilities.pushNew)(this.lines, _line["default"]);
153
186
  this.setCurrentLineType(this.sectionType);
154
- this.currentLine.key = this.currentKey;
187
+ this.currentLine.transposeKey = (_this$transposeKey = this.transposeKey) !== null && _this$transposeKey !== void 0 ? _this$transposeKey : this.currentKey;
188
+ this.currentLine.key = this.currentKey || this.key;
155
189
  return this.currentLine;
156
190
  }
157
191
  }, {
@@ -211,6 +245,8 @@ var Song = /*#__PURE__*/function () {
211
245
  if (tag.isMetaTag()) {
212
246
  this.setMetaData(tag.name, tag.value);
213
247
  } else if (tag.name === _tag.TRANSPOSE) {
248
+ this.transposeKey = tag.value;
249
+ } else if (tag.name === _tag.NEW_KEY) {
214
250
  this.currentKey = tag.value;
215
251
  } else {
216
252
  this.setSectionTypeFromTag(tag);
@@ -304,12 +340,7 @@ var Song = /*#__PURE__*/function () {
304
340
  }, {
305
341
  key: "clone",
306
342
  value: function clone() {
307
- var clonedSong = new Song();
308
- clonedSong.lines = this.lines.map(function (line) {
309
- return line.clone();
310
- });
311
- clonedSong.metadata = this.metadata.clone();
312
- return clonedSong;
343
+ return _classPrivateMethodGet(this, _mapItems, _mapItems2).call(this, null);
313
344
  }
314
345
  }, {
315
346
  key: "setMetaData",
@@ -333,11 +364,158 @@ var Song = /*#__PURE__*/function () {
333
364
  value: function getMetaData(name) {
334
365
  return this.metadata[name] || null;
335
366
  }
367
+ /**
368
+ * Returns a copy of the song with the capo value set to the specified capo. It changes:
369
+ * - the value for `capo` in the `metadata` set
370
+ * - any existing `capo` directive)
371
+ * @param {number|null} capo the capo. Passing `null` will:
372
+ * - remove the current key from `metadata`
373
+ * - remove any `capo` directive
374
+ * @returns {Song} The changed song
375
+ */
376
+
377
+ }, {
378
+ key: "setCapo",
379
+ value: function setCapo(capo) {
380
+ var updatedSong;
381
+
382
+ if (capo === null) {
383
+ updatedSong = _classPrivateMethodGet(this, _removeItem, _removeItem2).call(this, function (item) {
384
+ return item instanceof _tag["default"] && item.name === _tag.CAPO;
385
+ });
386
+ } else {
387
+ updatedSong = _classPrivateMethodGet(this, _updateItem, _updateItem2).call(this, function (item) {
388
+ return item instanceof _tag["default"] && item.name === _tag.CAPO;
389
+ }, function (item) {
390
+ return item.set({
391
+ value: capo
392
+ });
393
+ }, function (song) {
394
+ return _classPrivateMethodGet(song, _insertDirective, _insertDirective2).call(song, _tag.CAPO, capo);
395
+ });
396
+ }
397
+
398
+ updatedSong.metadata.set('capo', capo);
399
+ return updatedSong;
400
+ }
401
+ /**
402
+ * Returns a copy of the song with the key set to the specified key. It changes:
403
+ * - the value for `key` in the `metadata` set
404
+ * - any existing `key` directive
405
+ * - all chords, those are transposed according to the distance between the current and the new key
406
+ * @param {string} key The new key.
407
+ * @returns {Song} The changed song
408
+ */
409
+
410
+ }, {
411
+ key: "setKey",
412
+ value: function setKey(key) {
413
+ var transpose = _key["default"].distance(this.key, key);
414
+
415
+ var updatedSong = _classPrivateMethodGet(this, _mapItems, _mapItems2).call(this, function (item) {
416
+ if (item instanceof _tag["default"] && item.name === _tag.KEY) {
417
+ return item.set({
418
+ value: key
419
+ });
420
+ }
421
+
422
+ if (item instanceof _chord_lyrics_pair["default"]) {
423
+ var chordObj = _chord["default"].parse(item.chords);
424
+
425
+ if (chordObj) {
426
+ return item.set({
427
+ chords: chordObj.transpose(transpose).normalize(key)
428
+ });
429
+ }
430
+ }
431
+
432
+ return item;
433
+ });
434
+
435
+ updatedSong.metadata.set('key', key);
436
+ return updatedSong;
437
+ }
336
438
  }]);
337
439
 
338
440
  return Song;
339
441
  }();
340
442
 
443
+ function _insertDirective2(name, value) {
444
+ var _ref2 = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {},
445
+ _ref2$after = _ref2.after,
446
+ after = _ref2$after === void 0 ? null : _ref2$after;
447
+
448
+ var insertIndex = this.lines.findIndex(function (line) {
449
+ return line.items.some(function (item) {
450
+ return !(item instanceof _tag["default"]) || after && item instanceof _tag["default"] && item.name === after;
451
+ });
452
+ });
453
+ var newLine = new _line["default"]();
454
+ newLine.addTag(name, value);
455
+ var clonedSong = this.clone();
456
+ var lines = clonedSong.lines;
457
+ clonedSong.lines = [].concat(_toConsumableArray(lines.slice(0, insertIndex)), [newLine], _toConsumableArray(lines.slice(insertIndex)));
458
+ return clonedSong;
459
+ }
460
+
461
+ function _mapItems2(func) {
462
+ var clonedSong = new Song();
463
+ clonedSong.lines = this.lines.map(function (line) {
464
+ return line.mapItems(func);
465
+ });
466
+ clonedSong.metadata = this.metadata.clone();
467
+ return clonedSong;
468
+ }
469
+
470
+ function _mapLines2(func) {
471
+ var clonedSong = new Song();
472
+ clonedSong.lines = this.lines.map(function (line) {
473
+ return func(line.clone());
474
+ }).filter(function (line) {
475
+ return line;
476
+ });
477
+ clonedSong.metadata = this.metadata.clone();
478
+ return clonedSong;
479
+ }
480
+
481
+ function _updateItem2(findCallback, updateCallback, notFoundCallback) {
482
+ var found = false;
483
+
484
+ var updatedSong = _classPrivateMethodGet(this, _mapItems, _mapItems2).call(this, function (item) {
485
+ if (findCallback(item)) {
486
+ found = true;
487
+ return updateCallback(item);
488
+ }
489
+
490
+ return item;
491
+ });
492
+
493
+ if (!found) {
494
+ return notFoundCallback(updatedSong);
495
+ }
496
+
497
+ return updatedSong;
498
+ }
499
+
500
+ function _removeItem2(callback) {
501
+ return _classPrivateMethodGet(this, _mapLines, _mapLines2).call(this, function (line) {
502
+ var items = line.items;
503
+ var index = items.findIndex(callback);
504
+
505
+ if (index === -1) {
506
+ return line;
507
+ }
508
+
509
+ if (items.length === 1) {
510
+ return null;
511
+ }
512
+
513
+ return line.set({
514
+ items: [].concat(_toConsumableArray(items.slice(0, index)), _toConsumableArray(items.slice(index + 1)))
515
+ });
516
+ });
517
+ }
518
+
341
519
  var defineProperty = Object.defineProperty;
342
520
  var songPrototype = Song.prototype;
343
521