{"version":3,"sources":["../src/RecurringInterval.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,SAAS,EAAE,mBAAmB,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAI1E,qBAAa,iBAAiB,CAAC,CAAC,SAAS,QAAQ,CAAC,CAAC,CAAC,CAAE,YAAW,SAAS,EAAE,mBAAmB;IAC3F,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,QAAQ,CAAC,QAAQ,EAAE,CAAC,CAAC;IACrB,QAAQ,CAAC,YAAY,EAAE,OAAO,GAAG,KAAK,CAAC;gBAE3B,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,MAAM;gBAC7C,QAAQ,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,EAAE,MAAM,CAAC,EAAE,MAAM;IA6BvD,cAAc,CAAC,KAAK,EAAE,CAAC;IAiBvB,kBAAkB,CAAC,KAAK,EAAE,CAAC;IAiBzB,WAAW,IAAI,gBAAgB,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IAU9C,eAAe,CAAC,MAAM,EAAE,MAAM;IAM9B,qBAAqB,CAAC,KAAK,EAAE,CAAC;IAI9B,mBAAmB,CAAC,GAAG,EAAE,CAAC;IAI1B,wBAAwB,CAAC,QAAQ,EAAE,QAAQ;IAM3C,MAAM,CAAC,KAAK,EAAE,iBAAiB,CAAC,CAAC,CAAC;IAIlC,QAAQ,IAAI,MAAM;IASlB,MAAM;IAIN,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,MAAM;IAuB9B,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO;IAI3C,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,MAAM;IAI1B,CAAC,mBAAmB,CAAC,gBAAgB,CAAC,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO;IAQ1F,CAAC,mBAAmB,CAAC,cAAc,CAAC,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,MAAM;CAQ1E","file":"RecurringInterval.d.ts","sourcesContent":["/*!\r\n   Copyright 2019 Ron Buckton\r\n\r\n   Licensed under the Apache License, Version 2.0 (the \"License\");\r\n   you may not use this file except in compliance with the License.\r\n   You may obtain a copy of the License at\r\n\r\n       http://www.apache.org/licenses/LICENSE-2.0\r\n\r\n   Unless required by applicable law or agreed to in writing, software\r\n   distributed under the License is distributed on an \"AS IS\" BASIS,\r\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n   See the License for the specific language governing permissions and\r\n   limitations under the License.\r\n*/\r\nimport { isInt, normalizeString, RECURRINGINTERVAL_HASH_SEED } from './internal/core';\r\nimport { Temporal } from './types';\r\nimport { CivilDate } from './CivilDate';\r\nimport { CivilTime } from './CivilTime';\r\nimport { CivilDateTime } from './CivilDateTime';\r\nimport { OffsetTime } from './OffsetTime';\r\nimport { OffsetDateTime } from './OffsetDateTime';\r\nimport { ZonedDateTime } from './ZonedDateTime';\r\nimport { Duration } from './Duration';\r\nimport { Equatable, StructuralEquatable, Equaler } from '@esfx/equatable';\r\n\r\nconst intervalRegExp = /^R(?<repeat>\\d+)?\\/(?<second>(?:[^/]|\\[[^/]+\\])+)\\/(?<third>(?:[^/]|\\[[^/]+\\])+)$/;\r\n\r\nexport class RecurringInterval<T extends Temporal<T>> implements Equatable, StructuralEquatable {\r\n    readonly repeat: number; // 0 means indefinite\r\n    readonly duration: Duration;\r\n    readonly endpoint: T;\r\n    readonly endpointKind: \"start\" | \"end\";\r\n    \r\n    constructor(start: T, duration: Duration, repeat?: number);\r\n    constructor(duration: Duration, end: T, repeat?: number);\r\n    constructor(start: T | Duration, end: T | Duration, repeat: number = 0) {\r\n        if (!isInt(repeat) || repeat < 0) throw new RangeError();\r\n        if (start instanceof Duration) {\r\n            if (end instanceof Duration) throw new TypeError();\r\n            this.endpoint = end;\r\n            this.endpointKind = \"end\";\r\n            this.duration = start;\r\n            this.repeat = repeat;\r\n\r\n            if (this.endpoint.minus(this.duration).compareTo(this.endpoint) > 0) {\r\n                this.endpointKind = \"start\";\r\n                this.duration = this.duration.negate();\r\n            }\r\n        }\r\n        else {\r\n            if (!(end instanceof Duration)) throw new TypeError();\r\n            this.endpoint = start;\r\n            this.endpointKind = \"start\";\r\n            this.duration = end;\r\n            this.repeat = repeat;\r\n\r\n            if (this.endpoint.plus(this.duration).compareTo(this.endpoint) < 0) {\r\n                this.endpointKind = \"end\";\r\n                this.duration = this.duration.negate();\r\n            }\r\n        }\r\n    }\r\n\r\n    nextOccurrence(value: T) {\r\n        if (this.endpointKind === \"start\") {\r\n            for (const occurrence of this.occurrences()) {\r\n                if (occurrence[1].compareTo(value) > 0) return occurrence;\r\n            }\r\n        }\r\n        else {\r\n            if (this.endpoint.compareTo(value) <= 0) return undefined;\r\n            let last: [number, T] | undefined;\r\n            for (const occurrence of this.occurrences()) {\r\n                if (occurrence[1].compareTo(value) <= 0) break;\r\n                last = occurrence;\r\n            }\r\n            return last;\r\n        }\r\n    }\r\n\r\n    previousOccurrence(value: T) {\r\n        if (this.endpointKind === \"end\") {\r\n            for (const occurrence of this.occurrences()) {\r\n                if (occurrence[1].compareTo(value) < 0) return occurrence;\r\n            }\r\n        }\r\n        else {\r\n            if (this.endpoint.compareTo(value) >= 0) return undefined;\r\n            let last: [number, T] | undefined;\r\n            for (const occurrence of this.occurrences()) {\r\n                if (occurrence[1].compareTo(value) >= 0) break;\r\n                last = occurrence;\r\n            }\r\n            return last;\r\n        }\r\n    }\r\n\r\n    * occurrences(): IterableIterator<[number, T]> {\r\n        let current = this.endpoint;\r\n        for (let i = 0; this.repeat === 0 || i < this.repeat; i++) {\r\n            yield [i, current];\r\n            current = this.endpointKind === \"start\"\r\n                ? current.plus(this.duration) as T\r\n                : current.minus(this.duration) as T;\r\n        }\r\n    }\r\n\r\n    withRepetitions(repeat: number) {\r\n        return this.endpointKind === \"start\" \r\n            ? new RecurringInterval(this.endpoint, this.duration, repeat)\r\n            : new RecurringInterval(this.duration, this.endpoint, repeat);\r\n    }\r\n\r\n    withStartSameDuration(start: T) {\r\n        return new RecurringInterval(start, this.duration, this.repeat);\r\n    }\r\n\r\n    withEndSameDuration(end: T) {\r\n        return new RecurringInterval(this.duration, end, this.repeat);\r\n    }\r\n\r\n    withDurationSameEndpoint(duration: Duration) {\r\n        return this.endpointKind === \"start\" \r\n            ? new RecurringInterval(this.endpoint, duration, this.repeat)\r\n            : new RecurringInterval(duration, this.endpoint, this.repeat);\r\n    }\r\n\r\n    equals(other: RecurringInterval<T>) {\r\n        return this[Equatable.equals](other);\r\n    }\r\n\r\n    toString(): string {\r\n        const endpoint = this.endpoint.toISOString();\r\n        const duration = this.duration.toString();\r\n        const first = `R${this.repeat || \"\"}`;\r\n        const second = this.endpointKind === \"start\" ? endpoint : duration;\r\n        const third = this.endpointKind === \"end\" ? endpoint : duration;\r\n        return `${first}/${second}/${third}`;\r\n    }\r\n\r\n    toJSON() {\r\n        return this.toString();\r\n    }\r\n\r\n    static fromString(text: string) {\r\n        const match = intervalRegExp.exec(normalizeString(text));\r\n        if (match) {\r\n            const { repeat = \"\", second, third } = match.groups!;\r\n            if (second.startsWith(\"P\")) {\r\n                if (!third.startsWith(\"P\")) {\r\n                    return new RecurringInterval(\r\n                        Duration.fromString(second),\r\n                        parseTemporal(third),\r\n                        +repeat);\r\n                }\r\n            }\r\n            else {\r\n                if (!third.startsWith(\"P\")) throw new SyntaxError();\r\n                return new RecurringInterval(\r\n                    parseTemporal(second),\r\n                    Duration.fromString(third),\r\n                    +repeat);\r\n            }\r\n        }\r\n        throw new SyntaxError(`Invalid recurring interval string '${text}'.`);\r\n    }\r\n\r\n    [Equatable.equals](other: unknown): boolean {\r\n        return this[StructuralEquatable.structuralEquals](other, Equaler.defaultEqualer);\r\n    }\r\n\r\n    [Equatable.hash](): number {\r\n        return this[StructuralEquatable.structuralHash](Equaler.defaultEqualer);\r\n    }\r\n\r\n    [StructuralEquatable.structuralEquals](other: unknown, equaler: Equaler<unknown>): boolean {\r\n        return other instanceof RecurringInterval\r\n            && this.repeat === other.repeat\r\n            && this.endpointKind === other.endpointKind\r\n            && equaler.equals(this.duration, other.duration)\r\n            && equaler.equals(this.endpoint, other.endpoint);\r\n    }\r\n\r\n    [StructuralEquatable.structuralHash](equaler: Equaler<unknown>): number {\r\n        let hc = RECURRINGINTERVAL_HASH_SEED;\r\n        hc = ((hc << 7) | (hc >>> 25)) ^ Equaler.defaultEqualer.hash(this.repeat);\r\n        hc = ((hc << 7) | (hc >>> 25)) ^ Equaler.defaultEqualer.hash(this.endpointKind);\r\n        hc = ((hc << 7) | (hc >>> 25)) ^ equaler.hash(this.duration);\r\n        hc = ((hc << 7) | (hc >>> 25)) ^ equaler.hash(this.endpoint);\r\n        return hc;\r\n    }\r\n}\r\n\r\nfunction parseTemporal(text: string) {\r\n    try { return OffsetDateTime.fromString(text); } catch { }\r\n    try { return ZonedDateTime.fromString(text); } catch { }\r\n    try { return OffsetTime.fromString(text); } catch { }\r\n    try { return CivilDateTime.fromString(text); } catch { }\r\n    try { return CivilDate.fromString(text); } catch { }\r\n    try { return CivilTime.fromString(text); } catch { }\r\n    throw new SyntaxError(`Invalid temporal string '${text}'.`);\r\n}"],"sourceRoot":""}