diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 00000000..2384d1ee --- /dev/null +++ b/.eslintignore @@ -0,0 +1,4 @@ +dist/ +coverage/ +webpack.config.js +.eslintrc.js \ No newline at end of file diff --git a/.eslintrc.js b/.eslintrc.js index f7a2225b..c2e907b6 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -35,8 +35,9 @@ module.exports = { }, }, ], - '@typescript-eslint/naming-convention': 'error', + '@typescript-eslint/naming-convention': 'off', '@typescript-eslint/no-empty-function': 'error', + '@typescript-eslint/no-extra-semi': 'off', '@typescript-eslint/no-floating-promises': 'error', '@typescript-eslint/no-misused-new': 'error', '@typescript-eslint/no-unnecessary-qualifier': 'error', @@ -56,7 +57,7 @@ module.exports = { avoidEscape: true, }, ], - '@typescript-eslint/semi': ['error', 'never'], + '@typescript-eslint/semi': 'off', '@typescript-eslint/triple-slash-reference': [ 'error', { @@ -68,7 +69,7 @@ module.exports = { '@typescript-eslint/type-annotation-spacing': 'error', '@typescript-eslint/unified-signatures': 'error', 'brace-style': ['error', '1tbs'], - 'comma-dangle': 'error', + 'comma-dangle': 'off', curly: ['error', 'multi-line'], 'eol-last': 'error', eqeqeq: ['error', 'smart'], @@ -76,7 +77,6 @@ module.exports = { 'error', 'any', 'Number', - 'number', 'String', 'string', 'Boolean', @@ -91,6 +91,7 @@ module.exports = { 'jsdoc/newline-after-description': 'error', 'new-parens': 'error', 'no-caller': 'error', + 'no-case-declarations': 'off', 'no-cond-assign': 'error', 'no-constant-condition': 'error', 'no-control-regex': 'error', @@ -106,15 +107,15 @@ module.exports = { 'no-return-await': 'error', 'no-throw-literal': 'error', 'no-trailing-spaces': 'error', - 'no-underscore-dangle': 'error', - 'no-unused-expressions': 'error', + 'no-underscore-dangle': 'off', + 'no-unexpected-multiline': 'off', + 'no-unused-expressions': 'off', 'no-unused-labels': 'error', 'no-var': 'error', 'one-var': ['error', 'never'], - quotes: 'error', + quotes: 'off', radix: 'error', - semi: 'error', - 'space-before-function-paren': ['error', 'always'], + semi: 'off', 'space-in-parens': ['error', 'never'], 'spaced-comment': [ 'error', @@ -125,4 +126,12 @@ module.exports = { ], 'use-isnan': 'error', }, + overrides: [ + { + files: ['*.test.*'], + rules: { + '@typescript-eslint/no-unused-expressions': 'off', + }, + }, + ], } diff --git a/package.json b/package.json index b2e3e50f..37a98031 100644 --- a/package.json +++ b/package.json @@ -20,11 +20,13 @@ "url": "git://github.com/jakubroztocil/rrule.git" }, "scripts": { - "build": "yarn lint && yarn format-check && tsc && webpack && tsc dist/esm/**/*.d.ts", - "lint": "yarn eslint --ext .ts,.js --fix --config .eslintrc.js", + "prebuild": "yarn clean", + "build": "yarn lint && yarn format-check && tsc -b tsconfig.build.json && webpack && tsc dist/esm/**/*.d.ts", + "clean": "rm -rf dist/", + "lint": "yarn eslint . --fix --config .eslintrc.js", "format": "yarn prettier --write .", "format-check": "yarn prettier --check .", - "run-ts": "TS_NODE_PROJECT=tsconfig.test.json node --loader ts-node/esm", + "run-ts": "TS_NODE_PROJECT=tsconfig.json node --loader ts-node/esm", "test": "yarn run-ts ./node_modules/.bin/mocha **/*.test.ts", "test-ci": "yarn run-ts ./node_modules/.bin/nyc yarn run-ts ./node_modules/.bin/mocha **/*.test.ts" }, diff --git a/src/cache.ts b/src/cache.ts index 6c71b7cb..7f072699 100644 --- a/src/cache.ts +++ b/src/cache.ts @@ -47,17 +47,17 @@ export class Cache { if (what === 'all') { this.all = value as Date[] } else { - args!._value = value + args._value = value this[what].push(args as IterArgs) } } /** * @return false - not in the cache - * null - cached, but zero occurrences (before/after) - * Date - cached (before/after) - * [] - cached, but zero occurrences (all/between) - * [Date1, DateN] - cached (all/between) + * @return null - cached, but zero occurrences (before/after) + * @return Date - cached (before/after) + * @return [] - cached, but zero occurrences (all/between) + * @return [Date1, DateN] - cached (all/between) */ public _cacheGet( what: CacheKeys | 'all', @@ -68,7 +68,7 @@ export class Cache { const findCacheDiff = function (item: IterArgs) { for (let i = 0; i < argsKeys.length; i++) { const key = argsKeys[i] - if (!argsMatch(args![key], item[key])) { + if (!argsMatch(args[key], item[key])) { return true } } @@ -92,7 +92,7 @@ export class Cache { if (!cached && this.all) { // Not in the cache, but we already know all the occurrences, // so we can find the correct dates from the cached ones. - const iterResult = new IterResult(what, args!) + const iterResult = new IterResult(what, args) for (let i = 0; i < (this.all as Date[]).length; i++) { if (!iterResult.accept((this.all as Date[])[i])) break } diff --git a/src/datetime.ts b/src/datetime.ts index 0f646119..75e7fef4 100644 --- a/src/datetime.ts +++ b/src/datetime.ts @@ -145,7 +145,7 @@ export class DateTime extends Time { this.hour += Math.floor((23 - this.hour) / hours) * hours } - while (true) { + for (;;) { this.hour += hours const { div: dayDiv, mod: hourMod } = divmod(this.hour, 24) if (dayDiv) { @@ -169,7 +169,7 @@ export class DateTime extends Time { Math.floor((1439 - (this.hour * 60 + this.minute)) / minutes) * minutes } - while (true) { + for (;;) { this.minute += minutes const { div: hourDiv, mod: minuteMod } = divmod(this.minute, 60) if (hourDiv) { @@ -202,7 +202,7 @@ export class DateTime extends Time { ) * seconds } - while (true) { + for (;;) { this.second += seconds const { div: minuteDiv, mod: secondMod } = divmod(this.second, 60) if (minuteDiv) { diff --git a/src/dateutil.ts b/src/dateutil.ts index ddb4da4f..7e449538 100644 --- a/src/dateutil.ts +++ b/src/dateutil.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-namespace */ import { padStart } from './helpers' import { Time } from './datetime' diff --git a/src/fake-luxon.ts b/src/fake-luxon.ts deleted file mode 100644 index 253fedd2..00000000 --- a/src/fake-luxon.ts +++ /dev/null @@ -1,5 +0,0 @@ -export const DateTime = { - fromJSDate() { - throw new TypeError() - }, -} diff --git a/src/helpers.ts b/src/helpers.ts index 9df37513..a047382f 100644 --- a/src/helpers.ts +++ b/src/helpers.ts @@ -60,7 +60,7 @@ export const toArray = function (item: T | T[]): T[] { export function padStart( item: string | number, targetLength: number, - padString: string = ' ' + padString = ' ' ) { const str = String(item) targetLength = targetLength >> 0 @@ -99,7 +99,7 @@ export const split = function (str: string, sep: string, num: number) { * @param {number} a The dividend. * @param {number} b The divisor. * @return {number} a % b where the result is between 0 and b (either 0 <= x < b - * or b < x <= 0, depending on the sign of b). + * or b < x <= 0, depending on the sign of b). */ export const pymod = function (a: number, b: number) { const r = a % b @@ -120,6 +120,7 @@ export const empty = function (obj: T[] | null | undefined) { /** * Python-like boolean + * * @return {Boolean} value of an object/primitive, taking into account * the fact that in Python an empty list's/tuple's * boolean value is False, whereas in JS it's true diff --git a/src/index.ts b/src/index.ts index 0f0b7393..db9921aa 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,4 @@ -/*! +/* ! * rrule.js - Library for working with recurrence rules for calendar dates. * https://github.com/jakubroztocil/rrule * diff --git a/src/iter/index.ts b/src/iter/index.ts index c283e814..78ed82d1 100644 --- a/src/iter/index.ts +++ b/src/iter/index.ts @@ -20,24 +20,24 @@ export function iter( return emitResult(iterResult) } - let counterDate = DateTime.fromDate(dtstart) + const counterDate = DateTime.fromDate(dtstart) const ii = new Iterinfo(options) ii.rebuild(counterDate.year, counterDate.month) let timeset = makeTimeset(ii, counterDate, options) - while (true) { - let [dayset, start, end] = ii.getdayset(freq)( + for (;;) { + const [dayset, start, end] = ii.getdayset(freq)( counterDate.year, counterDate.month, counterDate.day ) - let filtered = removeFilteredDays(dayset, start, end, ii, options) + const filtered = removeFilteredDays(dayset, start, end, ii, options) if (notEmpty(bysetpos)) { - const poslist = buildPoslist(bysetpos, timeset!, start, end, ii, dayset) + const poslist = buildPoslist(bysetpos, timeset, start, end, ii, dayset) for (let j = 0; j < poslist.length; j++) { const res = poslist[j] @@ -67,8 +67,8 @@ export function iter( } const date = dateutil.fromOrdinal(ii.yearordinal + currentDay) - for (let k = 0; k < timeset!.length; k++) { - const time = timeset![k] + for (let k = 0; k < timeset.length; k++) { + const time = timeset[k] const res = dateutil.combine(date, time) if (until && res > until) { return emitResult(iterResult) @@ -131,10 +131,10 @@ function isFiltered( return ( (notEmpty(bymonth) && !includes(bymonth, ii.mmask[currentDay])) || - (notEmpty(byweekno) && !ii.wnomask![currentDay]) || + (notEmpty(byweekno) && !ii.wnomask[currentDay]) || (notEmpty(byweekday) && !includes(byweekday, ii.wdaymask[currentDay])) || (notEmpty(ii.nwdaymask) && !ii.nwdaymask[currentDay]) || - (byeaster !== null && !includes(ii.eastermask!, currentDay)) || + (byeaster !== null && !includes(ii.eastermask, currentDay)) || ((notEmpty(bymonthday) || notEmpty(bynmonthday)) && !includes(bymonthday, ii.mdaymask[currentDay]) && !includes(bynmonthday, ii.nmdaymask[currentDay])) || @@ -165,7 +165,7 @@ function removeFilteredDays( ) { let filtered = false for (let dayCounter = start; dayCounter < end; dayCounter++) { - let currentDay = dayset[dayCounter] as number + const currentDay = dayset[dayCounter] filtered = isFiltered(ii, currentDay, options) diff --git a/src/iterinfo/easter.ts b/src/iterinfo/easter.ts index 077b296a..271efea2 100644 --- a/src/iterinfo/easter.ts +++ b/src/iterinfo/easter.ts @@ -1,4 +1,4 @@ -export function easter(y: number, offset: number = 0) { +export function easter(y: number, offset = 0) { const a = y % 19 const b = Math.floor(y / 100) const c = y % 100 diff --git a/src/iterinfo/index.ts b/src/iterinfo/index.ts index c8ecf42c..89228b3b 100644 --- a/src/iterinfo/index.ts +++ b/src/iterinfo/index.ts @@ -18,6 +18,7 @@ export default class Iterinfo { public monthinfo: MonthInfo public eastermask: number[] | null + // eslint-disable-next-line no-empty-function constructor(private options: ParsedOptions) {} rebuild(year: number, month: number) { @@ -28,7 +29,7 @@ export default class Iterinfo { } if ( - notEmpty(options.bynweekday!) && + notEmpty(options.bynweekday) && (month !== this.lastmonth || year !== this.lastyear) ) { const { yearlen, mrange, wdaymask } = this.yearinfo diff --git a/src/iterinfo/monthinfo.ts b/src/iterinfo/monthinfo.ts index 051a6927..96dea471 100644 --- a/src/iterinfo/monthinfo.ts +++ b/src/iterinfo/monthinfo.ts @@ -49,9 +49,9 @@ export function rebuildMonth( const first = rang[0] const last = rang[1] - 1 - for (let k = 0; k < options.bynweekday!.length; k++) { + for (let k = 0; k < options.bynweekday.length; k++) { let i - const [wday, n] = options.bynweekday![k] + const [wday, n] = options.bynweekday[k] if (n < 0) { i = last + (n + 1) * 7 i -= pymod(wdaymask[i] - wday, 7) diff --git a/src/iterresult.ts b/src/iterresult.ts index 8bc669bb..49650c71 100644 --- a/src/iterresult.ts +++ b/src/iterresult.ts @@ -29,15 +29,13 @@ export default class IterResult { if (method === 'between') { this.maxDate = args.inc - ? args.before! - : new Date(args.before!.getTime() - 1) - this.minDate = args.inc - ? args.after! - : new Date(args.after!.getTime() + 1) + ? args.before + : new Date(args.before.getTime() - 1) + this.minDate = args.inc ? args.after : new Date(args.after.getTime() + 1) } else if (method === 'before') { - this.maxDate = args.inc ? args.dt! : new Date(args.dt!.getTime() - 1) + this.maxDate = args.inc ? args.dt : new Date(args.dt.getTime() - 1) } else if (method === 'after') { - this.minDate = args.inc ? args.dt! : new Date(args.dt!.getTime() + 1) + this.minDate = args.inc ? args.dt : new Date(args.dt.getTime() + 1) } } @@ -45,9 +43,9 @@ export default class IterResult { * Possibly adds a date into the result. * * @param {Date} date - the date isn't necessarly added to the result - * list (if it is too late/too early) + * list (if it is too late/too early) * @return {Boolean} true if it makes sense to continue the iteration - * false if we're done. + * false if we're done. */ accept(date: Date) { ++this.total @@ -81,6 +79,7 @@ export default class IterResult { /** * 'before' and 'after' return only one date, whereas 'all' * and 'between' an array. + * * @return {Date,Array?} */ getValue(): IterResultType { diff --git a/src/iterset.ts b/src/iterset.ts index df54483a..fec873b2 100644 --- a/src/iterset.ts +++ b/src/iterset.ts @@ -43,7 +43,7 @@ export function iterSet( } if (iterResult.method === 'between') { - evalExdate(iterResult.args.after!, iterResult.args.before!) + evalExdate(iterResult.args.after, iterResult.args.before) iterResult.accept = function (date) { const dt = Number(date) if (!_exdateHash[dt]) { diff --git a/src/nlp/index.ts b/src/nlp/index.ts index a3da90b2..f420d72c 100644 --- a/src/nlp/index.ts +++ b/src/nlp/index.ts @@ -4,7 +4,7 @@ import { RRule } from '../rrule' import { Frequency } from '../types' import ENGLISH, { Language } from './i18n' -/*! +/* ! * rrule.js - Library for working with recurrence rules for calendar dates. * https://github.com/jakubroztocil/rrule * @@ -35,13 +35,13 @@ import ENGLISH, { Language } from './i18n' * RULES * * Every ([n]) - * day(s) - * | [weekday], ..., (and) [weekday] - * | weekday(s) - * | week(s) - * | month(s) - * | [month], ..., (and) [month] - * | year(s) + * day(s) + * | [weekday], ..., (and) [weekday] + * | weekday(s) + * | week(s) + * | month(s) + * | [month], ..., (and) [month] + * | year(s) * * * Plus 0, 1, or multiple of these: @@ -67,10 +67,10 @@ import ENGLISH, { Language } from './i18n' * Definitely no supported for parsing: * * (for year): - * in week(s) [n], ..., (and) [n] + * in week(s) [n], ..., (and) [n] * - * on the [yearday], ..., (and) [n] day of the year - * on day [yearday], ..., (and) [n] + * on the [yearday], ..., (and) [n] day of the year + * on day [yearday], ..., (and) [n] * * * NON-TERMINALS @@ -81,10 +81,10 @@ import ENGLISH, { Language } from './i18n' * [nth-weekday]: first [weekday], 2nd [weekday], ... last [weekday], ... * [monthday]: first, 1., 2., 1st, 2nd, second, ... 31st, last day, 2nd last day, .. * [date]: - * [month] (0-31(,) ([year])), - * (the) 0-31.(1-12.([year])), - * (the) 0-31/(1-12/([year])), - * [weekday] + * - [month] (0-31(,) ([year])), + * - (the) 0-31.(1-12.([year])), + * - (the) 0-31/(1-12/([year])), + * - [weekday] * * [year]: 0000, 0001, ... 01, 02, .. * diff --git a/src/nlp/parsetext.ts b/src/nlp/parsetext.ts index e3b91bf7..e3495650 100644 --- a/src/nlp/parsetext.ts +++ b/src/nlp/parsetext.ts @@ -1,6 +1,6 @@ import ENGLISH, { Language } from './i18n' import { RRule } from '../rrule' -import { Options } from '../types' +import { ByWeekday, Options } from '../types' import { WeekdayStr } from '../weekday' // ============================================================================= @@ -31,7 +31,6 @@ class Parser { nextSymbol() { let best: RegExpExecArray | null let bestSymbol: string - const p = this this.symbol = null this.value = null @@ -40,9 +39,9 @@ class Parser { let rule: RegExp best = null - for (let name in this.rules) { + for (const name in this.rules) { rule = this.rules[name] - const match = rule.exec(p.text) + const match = rule.exec(this.text) if (match) { if (best === null || match[0].length > best[0].length) { best = match @@ -63,10 +62,8 @@ class Parser { this.value = null return } - // @ts-ignore } while (bestSymbol === 'SKIP') - // @ts-ignore this.symbol = bestSymbol this.value = best return true @@ -110,7 +107,7 @@ export default function parseText(text: string, language: Language = ENGLISH) { function S() { // every [n] ttr.expect('every') - let n = ttr.acceptNumber() + const n = ttr.acceptNumber() if (n) options.interval = parseInt(n[0], 10) if (ttr.isDone()) throw new Error('Unexpected end') @@ -191,15 +188,14 @@ export default function parseText(text: string, language: Language = ENGLISH) { while (ttr.accept('comma')) { if (ttr.isDone()) throw new Error('Unexpected end') - let wkd = decodeWKD() as keyof typeof RRule + const wkd = decodeWKD() as keyof typeof RRule if (!wkd) { throw new Error( 'Unexpected symbol ' + ttr.symbol + ', expected weekday' ) } - // @ts-ignore - options.byweekday.push(RRule[wkd]) + options.byweekday.push(RRule[wkd] as ByWeekday) ttr.nextSymbol() } MDAYs() @@ -227,7 +223,7 @@ export default function parseText(text: string, language: Language = ENGLISH) { while (ttr.accept('comma')) { if (ttr.isDone()) throw new Error('Unexpected end') - let m = decodeM() + const m = decodeM() if (!m) { throw new Error( 'Unexpected symbol ' + ttr.symbol + ', expected month' @@ -253,9 +249,9 @@ export default function parseText(text: string, language: Language = ENGLISH) { if (!(on || the)) return do { - let nth = decodeNTH() - let wkd = decodeWKD() - let m = decodeM() + const nth = decodeNTH() + const wkd = decodeWKD() + const m = decodeM() // nth | if (nth) { @@ -263,22 +259,20 @@ export default function parseText(text: string, language: Language = ENGLISH) { if (wkd) { ttr.nextSymbol() - if (!options.byweekday) options.byweekday = [] - // @ts-ignore - options.byweekday.push(RRule[wkd].nth(nth)) + if (!options.byweekday) options.byweekday = [] as ByWeekday[] + ;(options.byweekday as ByWeekday[]).push( + RRule[wkd as WeekdayStr].nth(nth) + ) } else { - if (!options.bymonthday) options.bymonthday = [] - // @ts-ignore - options.bymonthday.push(nth) + if (!options.bymonthday) options.bymonthday = [] as number[] + ;(options.bymonthday as number[]).push(nth) ttr.accept('day(s)') } // } else if (wkd) { ttr.nextSymbol() - if (!options.byweekday) options.byweekday = [] - - // @ts-ignore - options.byweekday.push(RRule[wkd]) + if (!options.byweekday) options.byweekday = [] as ByWeekday[] + ;(options.byweekday as ByWeekday[]).push(RRule[wkd as WeekdayStr]) } else if (ttr.symbol === 'weekday(s)') { ttr.nextSymbol() if (!options.byweekday) { @@ -304,10 +298,8 @@ export default function parseText(text: string, language: Language = ENGLISH) { } } else if (m) { ttr.nextSymbol() - if (!options.bymonth) options.bymonth = [] - - // @ts-ignore - options.bymonth.push(m) + if (!options.bymonth) options.bymonth = [] as number[] + ;(options.bymonth as number[]).push(m) } else { return } @@ -395,7 +387,7 @@ export default function parseText(text: string, language: Language = ENGLISH) { ttr.nextSymbol() return ttr.accept('last') ? -3 : 3 case 'nth': - const v = parseInt(ttr.value![1], 10) + const v = parseInt(ttr.value[1], 10) if (v < -366 || v > 366) throw new Error('Nth out of range: ' + v) ttr.nextSymbol() @@ -436,7 +428,7 @@ export default function parseText(text: string, language: Language = ENGLISH) { if (!date) throw new Error('Cannot parse until date:' + ttr.text) options.until = new Date(date) } else if (ttr.accept('for')) { - options.count = parseInt(ttr.value![0], 10) + options.count = parseInt(ttr.value[0], 10) ttr.expect('number') // ttr.expect('times') } diff --git a/src/nlp/totext.ts b/src/nlp/totext.ts index 1ed6d2f8..cbb614a1 100644 --- a/src/nlp/totext.ts +++ b/src/nlp/totext.ts @@ -71,8 +71,8 @@ export default class ToText { this.origOptions = rrule.origOptions if (this.origOptions.bymonthday) { - const bymonthday = ([] as number[]).concat(this.options.bymonthday!) - const bynmonthday = ([] as number[]).concat(this.options.bynmonthday!) + const bymonthday = ([] as number[]).concat(this.options.bymonthday) + const bynmonthday = ([] as number[]).concat(this.options.bynmonthday) bymonthday.sort((a, b) => a - b) bynmonthday.sort((a, b) => b - a) @@ -116,11 +116,11 @@ export default class ToText { return a.weekday - b.weekday } - this.byweekday.allWeeks!.sort(sortWeekDays) - this.byweekday.someWeeks!.sort(sortWeekDays) + this.byweekday.allWeeks.sort(sortWeekDays) + this.byweekday.someWeeks.sort(sortWeekDays) - if (!this.byweekday.allWeeks!.length) this.byweekday.allWeeks = null - if (!this.byweekday.someWeeks!.length) this.byweekday.someWeeks = null + if (!this.byweekday.allWeeks.length) this.byweekday.allWeeks = null + if (!this.byweekday.someWeeks.length) this.byweekday.someWeeks = null } else { this.byweekday = null } @@ -128,16 +128,17 @@ export default class ToText { /** * Test whether the rrule can be fully converted to text. + * * @param {RRule} rrule * @return {Boolean} */ static isFullyConvertible(rrule: RRule) { - let canConvert = true + const canConvert = true if (!(rrule.options.freq in ToText.IMPLEMENTED)) return false if (rrule.origOptions.until && rrule.origOptions.count) return false - for (let key in rrule.origOptions) { + for (const key in rrule.origOptions) { if (contains(['dtstart', 'wkst', 'freq'], key)) return true if (!contains(ToText.IMPLEMENTED[rrule.options.freq], key)) return false } @@ -153,16 +154,18 @@ export default class ToText { * Perform the conversion. Only some of the frequencies are supported. * If some of the rrule's options aren't supported, they'll * be omitted from the output an "(~ approximate)" will be appended. + * * @return {*} */ toString() { const gettext = this.gettext - if (!(this.options.freq! in ToText.IMPLEMENTED)) { + if (!(this.options.freq in ToText.IMPLEMENTED)) { return gettext('RRule error: Unable to fully convert this rrule to text') } this.text = [gettext('every')] + // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore this[RRule.FREQUENCIES[this.options.freq]]() @@ -192,20 +195,20 @@ export default class ToText { HOURLY() { const gettext = this.gettext - if (this.options.interval !== 1) this.add(this.options.interval!.toString()) + if (this.options.interval !== 1) this.add(this.options.interval.toString()) this.add( - this.plural(this.options.interval!) ? gettext('hours') : gettext('hour') + this.plural(this.options.interval) ? gettext('hours') : gettext('hour') ) } MINUTELY() { const gettext = this.gettext - if (this.options.interval !== 1) this.add(this.options.interval!.toString()) + if (this.options.interval !== 1) this.add(this.options.interval.toString()) this.add( - this.plural(this.options.interval!) + this.plural(this.options.interval) ? gettext('minutes') : gettext('minute') ) @@ -214,17 +217,17 @@ export default class ToText { DAILY() { const gettext = this.gettext - if (this.options.interval !== 1) this.add(this.options.interval!.toString()) + if (this.options.interval !== 1) this.add(this.options.interval.toString()) if (this.byweekday && this.byweekday.isWeekdays) { this.add( - this.plural(this.options.interval!) + this.plural(this.options.interval) ? gettext('weekdays') : gettext('weekday') ) } else { this.add( - this.plural(this.options.interval!) ? gettext('days') : gettext('day') + this.plural(this.options.interval) ? gettext('days') : gettext('day') ) } @@ -246,8 +249,8 @@ export default class ToText { const gettext = this.gettext if (this.options.interval !== 1) { - this.add(this.options.interval!.toString()).add( - this.plural(this.options.interval!) ? gettext('weeks') : gettext('week') + this.add(this.options.interval.toString()).add( + this.plural(this.options.interval) ? gettext('weeks') : gettext('week') ) } @@ -263,7 +266,7 @@ export default class ToText { } } else if (this.byweekday && this.byweekday.isEveryDay) { this.add( - this.plural(this.options.interval!) ? gettext('days') : gettext('day') + this.plural(this.options.interval) ? gettext('days') : gettext('day') ) } else { if (this.options.interval === 1) this.add(gettext('week')) @@ -286,17 +289,18 @@ export default class ToText { if (this.origOptions.bymonth) { if (this.options.interval !== 1) { - this.add(this.options.interval!.toString()).add(gettext('months')) - if (this.plural(this.options.interval!)) this.add(gettext('in')) + this.add(this.options.interval.toString()).add(gettext('months')) + if (this.plural(this.options.interval)) this.add(gettext('in')) } else { // this.add(gettext('MONTH')) } this._bymonth() } else { - if (this.options.interval !== 1) - this.add(this.options.interval!.toString()) + if (this.options.interval !== 1) { + this.add(this.options.interval.toString()) + } this.add( - this.plural(this.options.interval!) + this.plural(this.options.interval) ? gettext('months') : gettext('month') ) @@ -315,17 +319,18 @@ export default class ToText { if (this.origOptions.bymonth) { if (this.options.interval !== 1) { - this.add(this.options.interval!.toString()) + this.add(this.options.interval.toString()) this.add(gettext('years')) } else { // this.add(gettext('YEAR')) } this._bymonth() } else { - if (this.options.interval !== 1) - this.add(this.options.interval!.toString()) + if (this.options.interval !== 1) { + this.add(this.options.interval.toString()) + } this.add( - this.plural(this.options.interval!) ? gettext('years') : gettext('year') + this.plural(this.options.interval) ? gettext('years') : gettext('year') ) } @@ -360,10 +365,10 @@ export default class ToText { this.list(this.byweekday.allWeeks, this.weekdaytext, gettext('or')) ) .add(gettext('the')) - .add(this.list(this.bymonthday!, this.nth, gettext('or'))) + .add(this.list(this.bymonthday, this.nth, gettext('or'))) } else { this.add(gettext('on the')).add( - this.list(this.bymonthday!, this.nth, gettext('and')) + this.list(this.bymonthday, this.nth, gettext('and')) ) } // this.add(gettext('DAY')) @@ -371,17 +376,17 @@ export default class ToText { private _byweekday() { const gettext = this.gettext - if (this.byweekday!.allWeeks && !this.byweekday!.isWeekdays) { + if (this.byweekday.allWeeks && !this.byweekday.isWeekdays) { this.add(gettext('on')).add( - this.list(this.byweekday!.allWeeks, this.weekdaytext) + this.list(this.byweekday.allWeeks, this.weekdaytext) ) } - if (this.byweekday!.someWeeks) { - if (this.byweekday!.allWeeks) this.add(gettext('and')) + if (this.byweekday.someWeeks) { + if (this.byweekday.allWeeks) this.add(gettext('and')) this.add(gettext('on the')).add( - this.list(this.byweekday!.someWeeks, this.weekdaytext, gettext('and')) + this.list(this.byweekday.someWeeks, this.weekdaytext, gettext('and')) ) } } @@ -390,25 +395,24 @@ export default class ToText { const gettext = this.gettext this.add(gettext('at')).add( - this.list(this.origOptions.byhour!, undefined, gettext('and')) + this.list(this.origOptions.byhour, undefined, gettext('and')) ) } private _bymonth() { this.add( - this.list(this.options.bymonth!, this.monthtext, this.gettext('and')) + this.list(this.options.bymonth, this.monthtext, this.gettext('and')) ) } nth(n: number | string) { n = parseInt(n.toString(), 10) let nth: string - let npos: number const gettext = this.gettext if (n === -1) return gettext('last') - npos = Math.abs(n) + const npos = Math.abs(n) switch (npos) { case 1: case 21: @@ -437,7 +441,7 @@ export default class ToText { weekdaytext(wday: Weekday | number) { const weekday = isNumber(wday) ? (wday + 1) % 7 : wday.getJsWeekday() return ( - ((wday as Weekday).n ? this.nth((wday as Weekday).n!) + ' ' : '') + + ((wday as Weekday).n ? this.nth((wday as Weekday).n) + ' ' : '') + this.language.dayNames[weekday] ) } @@ -456,7 +460,7 @@ export default class ToText { arr: ByWeekday | ByWeekday[], callback?: GetText, finalDelim?: string, - delim: string = ',' + delim = ',' ) { if (!isArray(arr)) { arr = [arr] @@ -486,9 +490,9 @@ export default class ToText { function (o) { return o.toString() } - const self = this - const realCallback = function (arg: ByWeekday) { - return callback && callback.call(self, arg) + + const realCallback = (arg: ByWeekday) => { + return callback && callback.call(this, arg) } if (finalDelim) { diff --git a/src/optionstostring.ts b/src/optionstostring.ts index 6389fbdb..d0a9f72e 100644 --- a/src/optionstostring.ts +++ b/src/optionstostring.ts @@ -6,8 +6,8 @@ import dateutil from './dateutil' import { DateWithZone } from './datewithzone' export function optionsToString(options: Partial) { - let rrule: string[][] = [] - let dtstart: string = '' + const rrule: string[][] = [] + let dtstart = '' const keys: (keyof Options)[] = Object.keys(options) as (keyof Options)[] const defaultKeys = Object.keys(DEFAULT_OPTIONS) @@ -17,13 +17,13 @@ export function optionsToString(options: Partial) { let key = keys[i].toUpperCase() const value: any = options[keys[i]] - let outValue: string = '' + let outValue = '' if (!isPresent(value) || (isArray(value) && !value.length)) continue switch (key) { case 'FREQ': - outValue = RRule.FREQUENCIES[options.freq!] + outValue = RRule.FREQUENCIES[options.freq] break case 'WKST': if (isNumber(value)) { diff --git a/src/parseoptions.ts b/src/parseoptions.ts index 643855c7..da91b41f 100644 --- a/src/parseoptions.ts +++ b/src/parseoptions.ts @@ -19,8 +19,9 @@ export function initializeOptions(options: Partial) { // Shallow copy for options and origOptions and check for invalid for (const key of keys) { if (!includes(defaultKeys, key)) invalid.push(key) - if (dateutil.isDate(options[key]) && !dateutil.isValidDate(options[key])) + if (dateutil.isDate(options[key]) && !dateutil.isValidDate(options[key])) { invalid.push(key) + } } if (invalid.length) { diff --git a/src/parsestring.ts b/src/parsestring.ts index 14ca17b1..ad917486 100644 --- a/src/parsestring.ts +++ b/src/parsestring.ts @@ -79,6 +79,7 @@ function parseRrule(line: string) { case 'BYSECOND': const num = parseNumber(value) const optionKey = key.toLowerCase() + // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore options[optionKey] = num break diff --git a/src/rrule.ts b/src/rrule.ts index 13ab3da1..99611aed 100644 --- a/src/rrule.ts +++ b/src/rrule.ts @@ -61,7 +61,7 @@ export const defaultKeys = Object.keys(DEFAULT_OPTIONS) as (keyof Options)[] /** * * @param {Options?} options - see - * The only required option is `freq`, one of RRule.YEARLY, RRule.MONTHLY, ... + * - The only required option is `freq`, one of RRule.YEARLY, RRule.MONTHLY, ... * @constructor */ export class RRule implements QueryMethods { @@ -97,7 +97,7 @@ export class RRule implements QueryMethods { static readonly SA = Days.SA static readonly SU = Days.SU - constructor(options: Partial = {}, noCache: boolean = false) { + constructor(options: Partial = {}, noCache = false) { // RFC string this._cache = noCache ? null : new Cache() @@ -145,8 +145,8 @@ export class RRule implements QueryMethods { /** * @param {Function} iterator - optional function that will be called - * on each date that is added. It can return false - * to stop the iteration. + * on each date that is added. It can return false + * to stop the iteration. * @return Array containing all recurrences. */ all(iterator?: (d: Date, len: number) => boolean): Date[] { @@ -167,16 +167,18 @@ export class RRule implements QueryMethods { * The inc keyword defines what happens if after and/or before are * themselves occurrences. With inc == True, they will be included in the * list, if they are found in the recurrence set. + * * @return Array */ between( after: Date, before: Date, - inc: boolean = false, + inc = false, iterator?: (d: Date, len: number) => boolean ): Date[] { - if (!dateutil.isValidDate(after) || !dateutil.isValidDate(before)) + if (!dateutil.isValidDate(after) || !dateutil.isValidDate(before)) { throw new Error('Invalid date passed in to RRule.between') + } const args = { before, after, @@ -199,11 +201,13 @@ export class RRule implements QueryMethods { * Returns the last recurrence before the given datetime instance. * The inc keyword defines what happens if dt is an occurrence. * With inc == True, if dt itself is an occurrence, it will be returned. + * * @return Date or null */ before(dt: Date, inc = false): Date { - if (!dateutil.isValidDate(dt)) + if (!dateutil.isValidDate(dt)) { throw new Error('Invalid date passed in to RRule.before') + } const args = { dt: dt, inc: inc } let result = this._cacheGet('before', args) if (result === false) { @@ -217,11 +221,13 @@ export class RRule implements QueryMethods { * Returns the first recurrence after the given datetime instance. * The inc keyword defines what happens if dt is an occurrence. * With inc == True, if dt itself is an occurrence, it will be returned. + * * @return Date or null */ after(dt: Date, inc = false): Date { - if (!dateutil.isValidDate(dt)) + if (!dateutil.isValidDate(dt)) { throw new Error('Invalid date passed in to RRule.after') + } const args = { dt: dt, inc: inc } let result = this._cacheGet('after', args) if (result === false) { @@ -241,6 +247,7 @@ export class RRule implements QueryMethods { /** * Converts the rrule into its string representation + * * @see * @return String */ @@ -266,7 +273,7 @@ export class RRule implements QueryMethods { /** * @return a RRule instance with the same freq and options - * as this one (cache is not cloned) + * as this one (cache is not cloned) */ clone(): RRule { return new RRule(this.origOptions) diff --git a/src/rruleset.ts b/src/rruleset.ts index 6f10b2fd..876abf75 100644 --- a/src/rruleset.ts +++ b/src/rruleset.ts @@ -38,10 +38,10 @@ export class RRuleSet extends RRule { /** * * @param {Boolean?} noCache - * The same stratagy as RRule on cache, default to false + * The same stratagy as RRule on cache, default to false * @constructor */ - constructor(noCache: boolean = false) { + constructor(noCache = false) { super({}, noCache) this._rrule = [] @@ -172,9 +172,9 @@ export class RRuleSet extends RRule { /** * to generate recurrence field such as: - * DTSTART:19970902T010000Z - * RRULE:FREQ=YEARLY;COUNT=2;BYDAY=TU - * RRULE:FREQ=YEARLY;COUNT=1;BYDAY=TH + * DTSTART:19970902T010000Z + * RRULE:FREQ=YEARLY;COUNT=2;BYDAY=TU + * RRULE:FREQ=YEARLY;COUNT=1;BYDAY=TH */ toString() { return this.valueOf().join('\n') diff --git a/src/rrulestr.ts b/src/rrulestr.ts index 8086ff9a..f2f52892 100644 --- a/src/rrulestr.ts +++ b/src/rrulestr.ts @@ -16,7 +16,7 @@ export interface RRuleStrOptions { /** * RRuleStr - * To parse a set of rrule strings + * To parse a set of rrule strings */ const DEFAULT_OPTIONS: RRuleStrOptions = { dtstart: null, @@ -28,12 +28,14 @@ const DEFAULT_OPTIONS: RRuleStrOptions = { } export function parseInput(s: string, options: Partial) { - let rrulevals: Partial[] = [] + const rrulevals: Partial[] = [] let rdatevals: Date[] = [] - let exrulevals: Partial[] = [] + const exrulevals: Partial[] = [] let exdatevals: Date[] = [] - let { dtstart, tzid } = parseDtstart(s) + const parsedDtstart = parseDtstart(s) + const { dtstart } = parsedDtstart + let { tzid } = parsedDtstart const lines = splitIntoLines(s, options.unfold) @@ -51,7 +53,7 @@ export function parseInput(s: string, options: Partial) { break case 'RDATE': - const [_, rdateTzid] = /RDATE(?:;TZID=([^:=]+))?/i.exec(line)! + const [, rdateTzid] = /RDATE(?:;TZID=([^:=]+))?/i.exec(line) ?? [] if (rdateTzid && !tzid) { tzid = rdateTzid } @@ -127,7 +129,7 @@ function buildRule(s: string, options: Partial) { rset.exdate(date) }) - if (options.compatible && options.dtstart) rset.rdate(dtstart!) + if (options.compatible && options.dtstart) rset.rdate(dtstart) return rset } @@ -196,7 +198,7 @@ function extractName(line: string) { function breakDownLine(line: string) { const { name, value } = extractName(line) - let parms = name.split(';') + const parms = name.split(';') if (!parms) throw new Error('empty property name') return { diff --git a/test/lib/utils.ts b/test/lib/utils.ts index decc33b7..5487e2b1 100644 --- a/test/lib/utils.ts +++ b/test/lib/utils.ts @@ -41,9 +41,9 @@ export const datetime = function ( y: number, m: number, d: number, - h: number = 0, - i: number = 0, - s: number = 0 + h = 0, + i = 0, + s = 0 ) { return new Date(Date.UTC(y, m - 1, d, h, i, s)) } @@ -52,9 +52,9 @@ export const datetimeUTC = function ( y: number, m: number, d: number, - h: number = 0, - i: number = 0, - s: number = 0 + h = 0, + i = 0, + s = 0 ) { return new Date(Date.UTC(y, m - 1, d, h, i, s)) } @@ -64,7 +64,7 @@ export const datetimeUTC = function ( */ export const parse = function (str: string) { const parts = str.match(/^(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})(\d{2})/) - let [_, y, m, d, h, i, s] = parts + const [_, y, m, d, h, i, s] = parts const year = Number(y) const month = Number(m[0] === '0' ? m[1] : m) - 1 const day = Number(d[0] === '0' ? d[1] : d) @@ -88,7 +88,7 @@ export const testRecurring = function ( ) { let rule: any let method: string - let args: any + let args: unknown[] if (typeof testObj === 'function') { testObj = testObj() @@ -101,7 +101,7 @@ export const testRecurring = function ( } else { rule = testObj.rrule method = testObj.method - args = testObj.args + args = testObj.args ?? [] } // Use text and string representation of the rrule as the message. @@ -121,13 +121,13 @@ export const testRecurring = function ( itFunc(msg, function () { const ctx = this.test.ctx let time = Date.now() - let actualDates = rule[method].apply(rule, args) + let actualDates = rule[method](...args) time = Date.now() - time const maxTestDuration = 200 expect(time).to.be.lessThan( maxTestDuration, - `${rule}\' method "${method}" should finish in ${maxTestDuration} ms, but took ${time} ms` + `${rule}' method "${method}" should finish in ${maxTestDuration} ms, but took ${time} ms` ) if (!(actualDates instanceof Array)) actualDates = [actualDates] @@ -239,6 +239,7 @@ testRecurring.only = function (...args) { } testRecurring.skip = function () { + // eslint-disable-next-line prefer-spread, prefer-rest-params it.skip.apply(it, arguments) } diff --git a/test/parseoptions.test.ts b/test/parseoptions.test.ts index 6d8cde43..594f1d34 100644 --- a/test/parseoptions.test.ts +++ b/test/parseoptions.test.ts @@ -5,7 +5,6 @@ import { RRule } from '../src' describe('TZID', () => { it('leaves null when null', () => { const options = parseOptions({ tzid: null }) - // eslint-disable-next-line no-unused-expression expect(options.parsedOptions.tzid).to.be.null }) diff --git a/test/rrule.test.ts b/test/rrule.test.ts index a20d6a4f..ed315a11 100644 --- a/test/rrule.test.ts +++ b/test/rrule.test.ts @@ -3964,7 +3964,7 @@ describe('RRule', function () { rr.options.dtstart.getTime(), 'the supplied dtstart differs from RRule.options.dtstart' ) - let res: Date = rr.before(rr.after(rr.options.dtstart)) + const res: Date = rr.before(rr.after(rr.options.dtstart)) let resTimestamp: number if (res != null) resTimestamp = res.getTime() @@ -4020,7 +4020,6 @@ describe('RRule', function () { ].forEach(function (pair) { const rule = pair[0] const rr = RRule.fromString(rule) - // eslint-disable-next-line no-unused-expression expect(rr.toText()).to.be.ok // assert.equal(rr.toText(), pair[1]) -- can't test this because it reports in local time which varies by machine }) @@ -4052,7 +4051,7 @@ describe('RRule', function () { }) it('calculates byweekday recurrences correctly across DST boundaries', () => { - let rule = new RRule({ + const rule = new RRule({ freq: RRule.WEEKLY, dtstart: new Date(Date.UTC(2018, 9, 0, 0, 0, 0)), interval: 1, diff --git a/test/tslint.json b/test/tslint.json deleted file mode 100644 index bc325e44..00000000 --- a/test/tslint.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "extends": ["../tslint"], - "no-unused-expression": false -} diff --git a/tsconfig.build.json b/tsconfig.build.json new file mode 100644 index 00000000..d014c045 --- /dev/null +++ b/tsconfig.build.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "baseUrl": "./dist/esm", + "outDir": "./dist/esm", + "declaration": true, + "declarationMap": true, + "noImplicitAny": true, + "sourceMap": true, + "module": "es2015", + "moduleResolution": "node", + "noEmitOnError": true, + "target": "es5", + "importHelpers": true, + "esModuleInterop": true, + "rootDirs": ["./src/"] + }, + "include": ["./src/**/*"], + "exclude": ["node_modules", "./test/**/*"] +} diff --git a/tsconfig.json b/tsconfig.json index f5cc7aa6..d89ed13a 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,21 +1,15 @@ { "compilerOptions": { - "baseUrl": "./dist/esm", - "outDir": "./dist/esm", - "declaration": true, - "declarationMap": true, + "noEmit": true, "noImplicitAny": true, "sourceMap": true, - "module": "es2015", - "moduleResolution": "node", + "module": "commonjs", "noEmitOnError": true, - "target": "es5", - "jsx": "react", - "strictNullChecks": true, - "importHelpers": true, "esModuleInterop": true, + "target": "es6", + "baseUrl": ".", "rootDirs": ["./src/", "./test/"] }, - "include": ["./src/**/*"], - "exclude": ["node_modules", "./test/**/*"] + "include": ["./src/**/*", "./test/**/*"], + "exclude": ["node_modules"] } diff --git a/tsconfig.test.json b/tsconfig.test.json deleted file mode 100644 index 21fb3ee5..00000000 --- a/tsconfig.test.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "compilerOptions": { - "outDir": "./dist/es6", - "declaration": true, - "noImplicitAny": true, - "sourceMap": true, - "module": "commonjs", - "noEmitOnError": true, - "esModuleInterop": true, - "target": "es6", - "jsx": "react", - "baseUrl": ".", - "rootDirs": ["./src/", "./test/"] - }, - "include": ["./src/**/*", "./test/**/*"], - "exclude": ["node_modules"] -} diff --git a/webpack.config.js b/webpack.config.js index 12731b72..cd02f8eb 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -25,6 +25,9 @@ const commonConfig = { exclude: /node_modules/, loader: 'ts-loader', test: /\.ts$/, + options: { + configFile: 'tsconfig.build.json', + }, }, ], },