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