@hebcal/rest-api 5.1.1 → 5.1.3

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/dist/index.cjs CHANGED
@@ -1,4 +1,4 @@
1
- /*! @hebcal/rest-api v5.1.1 */
1
+ /*! @hebcal/rest-api v5.1.3 */
2
2
  'use strict';
3
3
 
4
4
  var core = require('@hebcal/core');
@@ -181,31 +181,32 @@ for (const [key, val] of Object.entries(alefbet)) {
181
181
  * negative numbers similar to how the JavaScript date formats
182
182
  * negative year numbers (e.g. `-37` is formatted as `-000037`).
183
183
  */
184
- function pad4(number) {
185
- if (number < 0) {
186
- return '-00' + pad4(-number);
184
+ function pad4(num) {
185
+ if (num < 0) {
186
+ return '-00' + pad4(-num);
187
187
  }
188
- else if (number < 10) {
189
- return '000' + number;
188
+ else if (num < 10) {
189
+ return '000' + num;
190
190
  }
191
- else if (number < 100) {
192
- return '00' + number;
191
+ else if (num < 100) {
192
+ return '00' + num;
193
193
  }
194
- else if (number < 1000) {
195
- return '0' + number;
194
+ else if (num < 1000) {
195
+ return '0' + num;
196
196
  }
197
- return String(number);
197
+ return String(num);
198
198
  }
199
199
  /**
200
200
  * Formats a number with leading zeros so the resulting string is 2 digits long.
201
201
  * Similar to `string.padStart(2, '0')`.
202
202
  */
203
- function pad2(number) {
204
- if (number < 10) {
205
- return '0' + number;
203
+ function pad2(num) {
204
+ if (num >= 0 && num < 10) {
205
+ return '0' + num;
206
206
  }
207
- return String(number);
207
+ return String(num);
208
208
  }
209
+
209
210
  /**
210
211
  * Returns YYYY-MM-DD in the local timezone
211
212
  */
@@ -237,6 +238,28 @@ const locales = new Map();
237
238
  let activeLocale;
238
239
  /** @private */
239
240
  let activeName;
241
+ /** @private */
242
+ function getEnOrdinal(n) {
243
+ const s = ['th', 'st', 'nd', 'rd'];
244
+ const v = n % 100;
245
+ return n + (s[(v - 20) % 10] || s[v] || s[0]);
246
+ }
247
+ /** @private */
248
+ function checkLocale(locale) {
249
+ if (typeof locale !== 'string') {
250
+ throw new TypeError(`Invalid locale name: ${locale}`);
251
+ }
252
+ return locale.toLowerCase();
253
+ }
254
+ /** @private */
255
+ function getExistingLocale(locale) {
256
+ const locale1 = checkLocale(locale);
257
+ const loc = locales.get(locale1);
258
+ if (!loc) {
259
+ throw new RangeError(`Locale '${locale}' not found`);
260
+ }
261
+ return loc;
262
+ }
240
263
  /**
241
264
  * A locale in Hebcal is used for translations/transliterations of
242
265
  * holidays. `@hebcal/hdate` supports four locales by default
@@ -279,14 +302,12 @@ class Locale {
279
302
  * @param data parsed data from a `.po` file.
280
303
  */
281
304
  static addLocale(locale, data) {
282
- if (typeof locale !== 'string') {
283
- throw new TypeError(`Invalid locale name: ${locale}`);
284
- }
305
+ locale = checkLocale(locale);
285
306
  if (typeof data.contexts !== 'object' ||
286
307
  typeof data.contexts[''] !== 'object') {
287
308
  throw new TypeError(`Locale '${locale}' invalid compact format`);
288
309
  }
289
- locales.set(locale.toLowerCase(), data.contexts['']);
310
+ locales.set(locale, data.contexts['']);
290
311
  }
291
312
  /**
292
313
  * Adds a translation to `locale`, replacing any previous translation.
@@ -295,15 +316,9 @@ class Locale {
295
316
  * @param translation Translation text
296
317
  */
297
318
  static addTranslation(locale, id, translation) {
298
- if (typeof locale !== 'string') {
299
- throw new TypeError(`Invalid locale name: ${locale}`);
300
- }
301
- const loc = locales.get(locale.toLowerCase());
302
- if (!loc) {
303
- throw new TypeError(`Unknown locale: ${locale}`);
304
- }
319
+ const loc = getExistingLocale(locale);
305
320
  if (typeof id !== 'string' || id.length === 0) {
306
- throw new TypeError(`Invalid id: ${id}`);
321
+ throw new TypeError(`Invalid id string: ${id}`);
307
322
  }
308
323
  const isArray = Array.isArray(translation);
309
324
  if (isArray) {
@@ -313,7 +328,7 @@ class Locale {
313
328
  }
314
329
  }
315
330
  else if (typeof translation !== 'string') {
316
- throw new TypeError(`Invalid translation: ${translation}`);
331
+ throw new TypeError(`Invalid translation string: ${translation}`);
317
332
  }
318
333
  loc[id] = isArray ? translation : [translation];
319
334
  }
@@ -323,13 +338,7 @@ class Locale {
323
338
  * @param data parsed data from a `.po` file.
324
339
  */
325
340
  static addTranslations(locale, data) {
326
- if (typeof locale !== 'string') {
327
- throw new TypeError(`Invalid locale name: ${locale}`);
328
- }
329
- const loc = locales.get(locale.toLowerCase());
330
- if (!loc) {
331
- throw new TypeError(`Unknown locale: ${locale}`);
332
- }
341
+ const loc = getExistingLocale(locale);
333
342
  if (typeof data.contexts !== 'object' ||
334
343
  typeof data.contexts[''] !== 'object') {
335
344
  throw new TypeError(`Locale '${locale}' invalid compact format`);
@@ -344,11 +353,8 @@ class Locale {
344
353
  * @param locale Locale name (i.e: `'he'`, `'fr'`)
345
354
  */
346
355
  static useLocale(locale) {
347
- const locale0 = locale.toLowerCase();
348
- const obj = locales.get(locale0);
349
- if (!obj) {
350
- throw new RangeError(`Locale '${locale}' not found`);
351
- }
356
+ const locale0 = checkLocale(locale);
357
+ const obj = getExistingLocale(locale0);
352
358
  activeName = alias[locale0] || locale0;
353
359
  activeLocale = obj;
354
360
  return activeLocale;
@@ -374,31 +380,24 @@ class Locale {
374
380
  const locale1 = locale === null || locale === void 0 ? void 0 : locale.toLowerCase();
375
381
  const locale0 = locale1 || activeName;
376
382
  if (!locale0) {
377
- return this.getEnOrdinal(n);
383
+ return getEnOrdinal(n);
378
384
  }
379
385
  switch (locale0) {
380
386
  case 'en':
381
387
  case 's':
382
388
  case 'a':
383
- case 'ashkenazi':
384
- case 'ashkenazi_litvish':
385
- case 'ashkenazi_poylish':
386
- case 'ashkenazi_standard':
387
- return this.getEnOrdinal(n);
389
+ return getEnOrdinal(n);
388
390
  case 'es':
389
391
  return n + 'º';
390
392
  case 'h':
391
393
  case 'he':
392
394
  case 'he-x-nonikud':
393
395
  return String(n);
394
- default:
395
- return n + '.';
396
396
  }
397
- }
398
- static getEnOrdinal(n) {
399
- const s = ['th', 'st', 'nd', 'rd'];
400
- const v = n % 100;
401
- return n + (s[(v - 20) % 10] || s[v] || s[0]);
397
+ if (locale0.startsWith('ashkenazi')) {
398
+ return getEnOrdinal(n);
399
+ }
400
+ return n + '.';
402
401
  }
403
402
  /**
404
403
  * Removes nekudot from Hebrew string
@@ -702,6 +701,82 @@ var holidayDescription0 = {
702
701
  "Yom Yerushalayim": "Jerusalem Day. Commemorates the re-unification of Jerusalem in 1967"
703
702
  };
704
703
 
704
+ /**
705
+ * Helper function to transform a string to make it more usable in a URL or filename.
706
+ * Converts to lowercase and replaces non-word characters with hyphen ('-').
707
+ * @example
708
+ * makeAnchor('Rosh Chodesh Adar II') // 'rosh-chodesh-adar-ii'
709
+ */
710
+ function makeAnchor(s) {
711
+ return s.toLowerCase()
712
+ .replace(/'/g, '')
713
+ .replace(/[^\w]/g, '-')
714
+ .replace(/-+/g, '-')
715
+ .replace(/^-/g, '')
716
+ .replace(/-$/g, '');
717
+ }
718
+
719
+ const parsha2id = new Map();
720
+ for (let id = 0; id < core.parshiot.length; id++) {
721
+ const name = core.parshiot[id];
722
+ parsha2id.set(makeAnchor(name), id + 1);
723
+ }
724
+ const doubledParshiyot = [
725
+ 'Vayakhel-Pekudei',
726
+ 'Tazria-Metzora',
727
+ 'Achrei Mot-Kedoshim',
728
+ 'Behar-Bechukotai',
729
+ 'Chukat-Balak',
730
+ 'Matot-Masei',
731
+ 'Nitzavim-Vayeilech',
732
+ ];
733
+ const doubled = new Set();
734
+ for (const name of doubledParshiyot) {
735
+ const anchor = makeAnchor(name);
736
+ doubled.add(anchor);
737
+ const [p1, p2] = anchor.split('-');
738
+ const id = parsha2id.get(p1);
739
+ parsha2id.set(anchor, id);
740
+ }
741
+ function parse8digitDateStr(date) {
742
+ const gy = date.substring(0, 4);
743
+ const gm = date.substring(4, 6);
744
+ const gd = date.substring(6, 8);
745
+ const yy = parseInt(gy, 10);
746
+ const mm = parseInt(gm, 10);
747
+ const dd = parseInt(gd, 10);
748
+ const dt = new Date(yy, mm - 1, dd);
749
+ if (yy < 100) {
750
+ dt.setFullYear(yy);
751
+ }
752
+ return dt;
753
+ }
754
+ function shortenSedrotUrl(u) {
755
+ const path = u.pathname;
756
+ const dash = path.lastIndexOf('-');
757
+ const dateStr = path.substring(dash + 1);
758
+ const name = path.substring(8, dash);
759
+ const id = parsha2id.get(name);
760
+ if (id && dateStr.length === 8) {
761
+ const dt = parse8digitDateStr(dateStr);
762
+ const hd = new core.HDate(dt);
763
+ let p = '/s/' + hd.getFullYear();
764
+ if (u.searchParams.get('i') === 'on') {
765
+ p += 'i';
766
+ u.searchParams.delete('i');
767
+ }
768
+ const id = parsha2id.get(name);
769
+ p += '/' + id;
770
+ if (doubled.has(name)) {
771
+ p += 'd';
772
+ }
773
+ u.pathname = p;
774
+ }
775
+ else {
776
+ u.pathname = '/s/' + path.substring(8);
777
+ }
778
+ }
779
+
705
780
  const LOC_FIELDS = ['elevation', 'admin1', 'asciiname', 'geo', 'zip', 'state', 'stateName', 'geonameid'];
706
781
  const holidayDescription = holidayDescription0;
707
782
  const countryNames = countryNames0;
@@ -732,20 +807,6 @@ function locationToPlainObj(location) {
732
807
  return { geo: 'none' };
733
808
  }
734
809
  }
735
- /**
736
- * Helper function to transform a string to make it more usable in a URL or filename.
737
- * Converts to lowercase and replaces non-word characters with hyphen ('-').
738
- * @example
739
- * makeAnchor('Rosh Chodesh Adar II') // 'rosh-chodesh-adar-ii'
740
- */
741
- function makeAnchor(s) {
742
- return s.toLowerCase()
743
- .replace(/'/g, '')
744
- .replace(/[^\w]/g, '-')
745
- .replace(/-+/g, '-')
746
- .replace(/^-/g, '')
747
- .replace(/-$/g, '');
748
- }
749
810
  function getDownloadFilename(options) {
750
811
  let fileName = 'hebcal';
751
812
  if (options.year) {
@@ -800,20 +861,30 @@ function getEventCategories(ev) {
800
861
  function renderTitleWithoutTime(ev) {
801
862
  return typeof ev.eventTime === 'undefined' ? ev.render() : ev.renderBrief();
802
863
  }
864
+ function shortLocationName(options) {
865
+ const loc = options.location;
866
+ if (!loc) {
867
+ return null;
868
+ }
869
+ if (options.preferAsciiName) {
870
+ const asciiname = loc.asciiname;
871
+ if (typeof asciiname === 'string') {
872
+ return asciiname;
873
+ }
874
+ }
875
+ return loc.getShortName();
876
+ }
803
877
  /**
804
878
  * Generates a title like "Hebcal 2020 Israel" or "Hebcal May 1993 Providence"
805
879
  */
806
880
  function getCalendarTitle(events, options) {
807
881
  let title = 'Hebcal';
808
- const location = options.location;
809
- const locationName = location === null || location === void 0 ? void 0 : location.getName();
882
+ const locationName = shortLocationName(options);
810
883
  if (options.yahrzeit) {
811
884
  title += ' Yahrzeits and Anniversaries';
812
885
  }
813
886
  else if (locationName) {
814
- const comma = locationName.indexOf(',');
815
- const name = (comma == -1) ? locationName : locationName.substring(0, comma);
816
- title += ' ' + name;
887
+ title += ' ' + locationName;
817
888
  }
818
889
  else if (options.il) {
819
890
  title += ' Israel';
@@ -908,7 +979,10 @@ function makeMemo(ev, il) {
908
979
  // fallthru
909
980
  }
910
981
  }
911
- return ev.memo || holidayDescription[ev.basename()];
982
+ if (ev.memo) {
983
+ return ev.memo;
984
+ }
985
+ return getHolidayDescription(ev);
912
986
  }
913
987
  /**
914
988
  * Appends utm_source and utm_medium parameters to a URL
@@ -930,7 +1004,7 @@ function appendIsraelAndTracking(url, il, utmSource, utmMedium, utmCampaign) {
930
1004
  u.pathname = '/h/' + path.substring(10);
931
1005
  }
932
1006
  else if (isSedrot) {
933
- u.pathname = '/s/' + path.substring(8);
1007
+ shortenSedrotUrl(u);
934
1008
  }
935
1009
  else { // isOmer
936
1010
  u.pathname = '/o/' + path.substring(6);
@@ -1026,8 +1100,9 @@ function eventToCsv(ev, options) {
1026
1100
  const mask = ev.getFlags();
1027
1101
  if (timed && typeof options.location === 'object') {
1028
1102
  const locationName = options.location.getShortName();
1029
- const comma = locationName.indexOf(',');
1030
- loc = (comma === -1) ? locationName : locationName.substring(0, comma);
1103
+ if (locationName) {
1104
+ loc = locationName;
1105
+ }
1031
1106
  }
1032
1107
  else {
1033
1108
  const category = CATEGORY[getEventCategories(ev)[0]];
@@ -1181,7 +1256,7 @@ function eventToClassicApiObject(ev, options, leyning$1 = true) {
1181
1256
  d: core.gematriya(dd),
1182
1257
  };
1183
1258
  }
1184
- const memo = ev.memo || holidayDescription[ev.basename()];
1259
+ const memo = ev.memo || getHolidayDescription(ev);
1185
1260
  if (typeof memo === 'string' && memo.length !== 0) {
1186
1261
  result.memo = memo.normalize();
1187
1262
  }
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from './csv';
2
+ export * from './makeAnchor';
2
3
  export * from './common';
3
4
  export * from './classic-rest-api';
4
5
  export * from './rss';