From 76e9abdceb70632bc4472aacb347bc4e994e742f Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Mon, 3 Jan 2022 01:54:58 -0500 Subject: [PATCH] Removes dayjs & uses platform Intl formatting --- package.json | 3 +- src/config.ts | 11 +- src/git/formatters/commitFormatter.ts | 6 +- src/git/models/commit.ts | 12 +- src/git/models/contributor.ts | 4 +- src/git/models/repository.ts | 10 +- src/system/date.ts | 338 ++++++++++++------ src/webviews/apps/shared/appWithConfigBase.ts | 4 +- src/webviews/apps/shared/date.ts | 16 +- src/webviews/apps/tsconfig.json | 2 +- yarn.lock | 41 +-- 11 files changed, 267 insertions(+), 180 deletions(-) diff --git a/package.json b/package.json index ba6b6f5466e2d..9b6de492f8502 100644 --- a/package.json +++ b/package.json @@ -10135,7 +10135,6 @@ "@octokit/graphql": "4.8.0", "@vscode/codicons": "0.0.27", "chroma-js": "2.1.2", - "dayjs": "1.10.7", "iconv-lite": "0.6.3", "lodash-es": "4.17.21", "md5.js": "1.3.5", @@ -10166,7 +10165,7 @@ "eslint-config-prettier": "8.3.0", "eslint-import-resolver-typescript": "2.5.0", "eslint-plugin-anti-trojan-source": "1.1.0", - "eslint-plugin-import": "2.25.3", + "eslint-plugin-import": "2.25.4", "fork-ts-checker-webpack-plugin": "6.5.0", "html-loader": "3.0.1", "html-webpack-plugin": "5.5.0", diff --git a/src/config.ts b/src/config.ts index bb9215977f4e9..b7ed26bfbf42e 100644 --- a/src/config.ts +++ b/src/config.ts @@ -1,4 +1,5 @@ 'use strict'; +import { DateTimeFormat } from './system/date'; export const enum OutputLevel { Silent = 'silent', @@ -12,7 +13,7 @@ export interface Config { blame: { avatars: boolean; compact: boolean; - dateFormat: string | null; + dateFormat: DateTimeFormat | string | null; format: string; heatmap: { enabled: boolean; @@ -41,12 +42,12 @@ export interface Config { scrollable: boolean; }; debug: boolean; - defaultDateFormat: string | null; - defaultDateShortFormat: string | null; + defaultDateFormat: DateTimeFormat | string | null; + defaultDateShortFormat: DateTimeFormat | string | null; defaultDateSource: DateSource; defaultDateStyle: DateStyle; defaultGravatarsStyle: GravatarDefaultStyle; - defaultTimeFormat: string | null; + defaultTimeFormat: DateTimeFormat | string | null; fileAnnotations: { command: string | null; }; @@ -127,7 +128,7 @@ export interface Config { statusBar: { alignment: 'left' | 'right'; command: StatusBarCommand; - dateFormat: string | null; + dateFormat: DateTimeFormat | string | null; enabled: boolean; format: string; reduceFlicker: boolean; diff --git a/src/git/formatters/commitFormatter.ts b/src/git/formatters/commitFormatter.ts index 474eff3ee3e12..c22cb257c3b21 100644 --- a/src/git/formatters/commitFormatter.ts +++ b/src/git/formatters/commitFormatter.ts @@ -87,7 +87,7 @@ export class CommitFormatter extends Formatter { } private get _authorDateAgoShort() { - return this._item.formatCommitterDateFromNow('en-short'); + return this._item.formatCommitterDateFromNow(true); } private get _committerDate() { @@ -99,7 +99,7 @@ export class CommitFormatter extends Formatter { } private get _committerDateAgoShort() { - return this._item.formatCommitterDateFromNow('en-short'); + return this._item.formatCommitterDateFromNow(true); } private get _date() { @@ -111,7 +111,7 @@ export class CommitFormatter extends Formatter { } private get _dateAgoShort() { - return this._item.formatDateFromNow('en-short'); + return this._item.formatDateFromNow(true); } private get _pullRequestDate() { diff --git a/src/git/models/commit.ts b/src/git/models/commit.ts index df7b2b3a7d118..f16b13193cf57 100644 --- a/src/git/models/commit.ts +++ b/src/git/models/commit.ts @@ -195,8 +195,8 @@ export abstract class GitCommit implements GitRevisionReference { return this.authorDateFormatter.format(format); } - formatAuthorDateFromNow(locale?: string) { - return this.authorDateFormatter.fromNow(locale); + formatAuthorDateFromNow(short?: boolean) { + return this.authorDateFormatter.fromNow(short); } @memoize(format => (format == null ? 'MMMM Do, YYYY h:mma' : format)) @@ -208,8 +208,8 @@ export abstract class GitCommit implements GitRevisionReference { return this.committerDateFormatter.format(format); } - formatCommitterDateFromNow(locale?: string) { - return this.committerDateFormatter.fromNow(locale); + formatCommitterDateFromNow(short?: boolean) { + return this.committerDateFormatter.fromNow(short); } @memoize(format => (format == null ? 'MMMM Do, YYYY h:mma' : format)) @@ -221,8 +221,8 @@ export abstract class GitCommit implements GitRevisionReference { return this.dateFormatter.format(format); } - formatDateFromNow(locale?: string) { - return this.dateFormatter.fromNow(locale); + formatDateFromNow(short?: boolean) { + return this.dateFormatter.fromNow(short); } getFormattedPath(options: { relativeTo?: string; suffix?: string; truncateTo?: number } = {}): string { diff --git a/src/git/models/contributor.ts b/src/git/models/contributor.ts index 7a0c484cfaa35..0a2166f8ef496 100644 --- a/src/git/models/contributor.ts +++ b/src/git/models/contributor.ts @@ -86,8 +86,8 @@ export class GitContributor { return this.dateFormatter.format(format); } - formatDateFromNow(locale?: string) { - return this.dateFormatter.fromNow(locale); + formatDateFromNow(short?: boolean) { + return this.dateFormatter.fromNow(short); } getAvatarUri(options?: { defaultStyle?: GravatarDefaultStyle; size?: number }): Uri | Promise { diff --git a/src/git/models/repository.ts b/src/git/models/repository.ts index 444de04d8566a..2a29ea720d0df 100644 --- a/src/git/models/repository.ts +++ b/src/git/models/repository.ts @@ -40,6 +40,10 @@ import { GitStash } from './stash'; import { GitStatus } from './status'; import { GitTag, TagSortOptions } from './tag'; +const millisecondsPerMinute = 60 * 1000; +const millisecondsPerHour = 60 * 60 * 1000; +const millisecondsPerDay = 24 * 60 * 60 * 1000; + export const enum RepositoryChange { // FileSystem = 'filesystem', Unknown = 'unknown', @@ -145,7 +149,7 @@ export interface RepositoryFileSystemChangeEvent { export class Repository implements Disposable { static formatLastFetched(lastFetched: number, short: boolean = true): string { const formatter = Dates.getFormatter(new Date(lastFetched)); - if (Date.now() - lastFetched < Dates.MillisecondsPerDay) { + if (Date.now() - lastFetched < millisecondsPerDay) { return formatter.fromNow(); } @@ -164,8 +168,8 @@ export class Repository implements Disposable { static getLastFetchedUpdateInterval(lastFetched: number): number { const timeDiff = Date.now() - lastFetched; - return timeDiff < Dates.MillisecondsPerDay - ? (timeDiff < Dates.MillisecondsPerHour ? Dates.MillisecondsPerMinute : Dates.MillisecondsPerHour) / 2 + return timeDiff < millisecondsPerDay + ? (timeDiff < millisecondsPerHour ? millisecondsPerMinute : millisecondsPerHour) / 2 : 0; } diff --git a/src/system/date.ts b/src/system/date.ts index 3a71f0ea24991..fabbd694ebc4c 100644 --- a/src/system/date.ts +++ b/src/system/date.ts @@ -1,125 +1,235 @@ 'use strict'; -import * as dayjs from 'dayjs'; -import * as advancedFormat from 'dayjs/plugin/advancedFormat'; -import * as relativeTime from 'dayjs/plugin/relativeTime'; -import * as updateLocale from 'dayjs/plugin/updateLocale'; - -dayjs.default.extend(advancedFormat.default); -dayjs.default.extend(relativeTime.default, { - thresholds: [ - { l: 's', r: 44, d: 'second' }, - { l: 'm', r: 89 }, - { l: 'mm', r: 44, d: 'minute' }, - { l: 'h', r: 89 }, - { l: 'hh', r: 21, d: 'hour' }, - { l: 'd', r: 35 }, - { l: 'dd', r: 6, d: 'day' }, - { l: 'w', r: 7 }, - { l: 'ww', r: 3, d: 'week' }, - { l: 'M', r: 4 }, - { l: 'MM', r: 10, d: 'month' }, - { l: 'y', r: 17 }, - { l: 'yy', d: 'year' }, - ], -}); -dayjs.default.extend(updateLocale.default); - -dayjs.default.updateLocale('en', { - relativeTime: { - future: 'in %s', - past: '%s ago', - s: 'seconds', - m: 'a minute', - mm: '%d minutes', - h: 'an hour', - hh: '%d hours', - d: 'a day', - dd: '%d days', - w: 'a week', - ww: '%d weeks', - M: 'a month', - MM: '%d months', - y: 'a year', - yy: '%d years', - }, -}); - -const shortLocale = { - name: 'en-short', - weekdays: 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_'), - months: 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_'), - weekStart: 1, - weekdaysShort: 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'), - monthsShort: 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'), - weekdaysMin: 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'), - // relativeTime: { - // future: 'in %s', - // past: '%s', - // s: 'now', - // m: '1 min', - // mm: '%d mins', - // h: '1 hr', - // hh: '%d hrs', - // d: '1 day', - // dd: '%d days', - // w: '1 wk', - // ww: '%d wks', - // M: '1 mo', - // MM: '%d mos', - // y: '1 yr', - // yy: '%d yrs', - // }, - relativeTime: { - future: 'in %s', - past: '%s', - s: 'now', - m: '1m', - mm: '%dm', - h: '1h', - hh: '%dh', - d: '1d', - dd: '%dd', - w: '1wk', - ww: '%dwk', - M: '1mo', - MM: '%dmo', - y: '1yr', - yy: '%dyr', - }, - formats: { - LTS: 'h:mm:ss A', - LT: 'h:mm A', - L: 'MM/DD/YYYY', - LL: 'MMMM D, YYYY', - LLL: 'MMMM D, YYYY h:mm A', - LLLL: 'dddd, MMMM D, YYYY h:mm A', - }, - ordinal: (n: number) => { - const s = ['th', 'st', 'nd', 'rd']; - const v = n % 100; - return `[${n}${s[(v - 20) % 10] || s[v] || s[0]}]`; - }, -}; - -dayjs.default.locale('en-short', shortLocale, true); - -export const MillisecondsPerMinute = 60000; // 60 * 1000 -export const MillisecondsPerHour = 3600000; // 60 * 60 * 1000 -export const MillisecondsPerDay = 86400000; // 24 * 60 * 60 * 1000 + +// NOTE@eamodio If this changes we need to update the replacement function too (since its parameter number/order relies on the matching) +const customDateTimeFormatParserRegex = + /(?\[.*?\])|(?YYYY|YY)|(?M{1,4})|(?Do|DD?)|(?d{2,4})|(?HH?|hh?)|(?mm?)|(?ss?)|(?SSS)|(?A|a)|(?ZZ?)/g; +const dateTimeFormatCache = new Map(); +const dateTimeFormatRegex = /(?full|long|medium|short)(?:\+(?full|long|medium|short))?/; +let defaultRelativeTimeFormat: InstanceType | undefined; +let defaultShortRelativeTimeFormat: InstanceType | undefined; +let locale: string | undefined; +const relativeUnitThresholds: [Intl.RelativeTimeFormatUnit, number, string][] = [ + ['year', 24 * 60 * 60 * 1000 * 365, 'yr'], + ['month', (24 * 60 * 60 * 1000 * 365) / 12, 'mo'], + ['week', 24 * 60 * 60 * 1000 * 7, 'wk'], + ['day', 24 * 60 * 60 * 1000, 'd'], + ['hour', 60 * 60 * 1000, 'h'], + ['minute', 60 * 1000, 'm'], + ['second', 1000, 's'], +]; + +type DateStyle = 'full' | 'long' | 'medium' | 'short'; +type TimeStyle = 'full' | 'long' | 'medium' | 'short'; +export type DateTimeFormat = DateStyle | `${DateStyle}+${TimeStyle}`; export interface DateFormatter { - fromNow(locale?: string): string; - format(format: string): string; + fromNow(short?: boolean): string; + format(format: DateTimeFormat | string | null | undefined): string; } export function getFormatter(date: Date): DateFormatter { - const formatter = dayjs.default(date); return { - fromNow: function (locale?: string) { - return (locale ? formatter.locale(locale) : formatter).fromNow(); + fromNow: function (short?: boolean) { + const elapsed = date.getTime() - new Date().getTime(); + + for (const [unit, threshold, shortUnit] of relativeUnitThresholds) { + const elapsedABS = Math.abs(elapsed); + if (elapsedABS >= threshold || threshold === 1000 /* second */) { + if (short) { + if (locale == null) { + if (defaultShortRelativeTimeFormat != null) { + locale = defaultShortRelativeTimeFormat.resolvedOptions().locale; + } else if (defaultRelativeTimeFormat != null) { + locale = defaultRelativeTimeFormat.resolvedOptions().locale; + } else { + defaultShortRelativeTimeFormat = new Intl.RelativeTimeFormat(undefined, { + localeMatcher: 'best fit', + numeric: 'always', + style: 'narrow', + }); + locale = defaultShortRelativeTimeFormat.resolvedOptions().locale; + } + } + + if (locale === 'en' || locale?.startsWith('en-')) { + const value = Math.round(elapsedABS / threshold); + return `${value}${shortUnit}`; + } + + if (defaultShortRelativeTimeFormat == null) { + defaultShortRelativeTimeFormat = new Intl.RelativeTimeFormat(undefined, { + localeMatcher: 'best fit', + numeric: 'always', + style: 'narrow', + }); + } + + return defaultShortRelativeTimeFormat.format(Math.round(elapsed / threshold), unit); + } + + if (defaultRelativeTimeFormat == null) { + defaultRelativeTimeFormat = new Intl.RelativeTimeFormat(undefined, { + localeMatcher: 'best fit', + numeric: 'auto', + style: 'long', + }); + } + return defaultRelativeTimeFormat.format(Math.round(elapsed / threshold), unit); + } + } + + return ''; }, - format: function (format: string) { - return formatter.format(format); + format: function (format: 'full' | 'long' | 'medium' | 'short' | string | null | undefined) { + format = format ?? undefined; + + let formatter = dateTimeFormatCache.get(format); + if (formatter == null) { + const options = getDateTimeFormatOptionsFromFormatString(format); + formatter = new Intl.DateTimeFormat(undefined, options); + dateTimeFormatCache.set(format, formatter); + } + + if (format == null || dateTimeFormatRegex.test(format)) { + return formatter.format(date); + } + + const parts = formatter.formatToParts(date); + return format.replace( + customDateTimeFormatParserRegex, + ( + _match, + literal, + _year, + _month, + _day, + _weekday, + _hour, + _minute, + _second, + _fractionalSecond, + _dayPeriod, + _timeZoneName, + _offset, + _s, + groups, + ) => { + if (literal != null) return (literal as string).substring(1, literal.length - 1); + + for (const key in groups) { + const value = groups[key]; + if (value == null) continue; + + const part = parts.find(p => p.type === key); + + if (value === 'Do' && part?.type === 'day') { + return formatWithOrdinal(Number(part.value)); + } else if (value === 'a' && part?.type === 'dayPeriod') { + return part.value.toLocaleLowerCase(); + } + return part?.value ?? ''; + } + + return ''; + }, + ); }, }; } + +function getDateTimeFormatOptionsFromFormatString( + format: DateTimeFormat | string | undefined, +): Intl.DateTimeFormatOptions { + if (format == null) return { localeMatcher: 'best fit', dateStyle: 'full', timeStyle: 'short' }; + + const match = dateTimeFormatRegex.exec(format); + if (match?.groups != null) { + const { dateStyle, timeStyle } = match.groups; + return { + localeMatcher: 'best fit', + dateStyle: (dateStyle as Intl.DateTimeFormatOptions['dateStyle']) || 'full', + timeStyle: (timeStyle as Intl.DateTimeFormatOptions['timeStyle']) || undefined, + }; + } + + const options: Intl.DateTimeFormatOptions = { localeMatcher: 'best fit' }; + + for (const { groups } of format.matchAll(customDateTimeFormatParserRegex)) { + if (groups == null) continue; + + for (const key in groups) { + const value = groups[key]; + if (value == null) continue; + + switch (key) { + case 'year': + options.year = value.length === 4 ? 'numeric' : '2-digit'; + break; + case 'month': + switch (value.length) { + case 4: + options.month = 'long'; + break; + case 3: + options.month = 'short'; + break; + case 2: + options.month = '2-digit'; + break; + case 1: + options.month = 'numeric'; + break; + } + break; + case 'day': + if (value === 'DD') { + options.day = '2-digit'; + } else { + options.day = 'numeric'; + } + break; + case 'weekday': + switch (value.length) { + case 4: + options.weekday = 'long'; + break; + case 3: + options.weekday = 'short'; + break; + case 2: + options.weekday = 'narrow'; + break; + } + break; + case 'hour': + options.hour = value.length === 2 ? '2-digit' : 'numeric'; + options.hour12 = value === 'hh' || value === 'h'; + break; + case 'minute': + options.minute = value.length === 2 ? '2-digit' : 'numeric'; + break; + case 'second': + options.second = value.length === 2 ? '2-digit' : 'numeric'; + break; + case 'fractionalSecond': + (options as any).fractionalSecondDigits = 3; + break; + case 'dayPeriod': + options.dayPeriod = 'narrow'; + options.hour12 = true; + break; + case 'timeZoneName': + options.timeZoneName = (value.length === 2 ? 'longOffset' : 'shortOffset') as any; + break; + } + } + } + + return options; +} + +const ordinals = ['th', 'st', 'nd', 'rd']; +function formatWithOrdinal(n: number): string { + const v = n % 100; + return `${n}${ordinals[(v - 20) % 10] ?? ordinals[v] ?? ordinals[0]}`; +} diff --git a/src/webviews/apps/shared/appWithConfigBase.ts b/src/webviews/apps/shared/appWithConfigBase.ts index ee450c5cba956..bdf8b24b2f470 100644 --- a/src/webviews/apps/shared/appWithConfigBase.ts +++ b/src/webviews/apps/shared/appWithConfigBase.ts @@ -9,12 +9,12 @@ import { PreviewConfigurationCommandType, UpdateConfigurationCommandType, } from '../../protocol'; -import { getDateFormatter } from '../shared/date'; +import { getFormatter } from '../shared/date'; import { App } from './appBase'; import { DOM } from './dom'; const offset = (new Date().getTimezoneOffset() / 60) * 100; -const dateFormatter = getDateFormatter( +const dateFormatter = getFormatter( new Date(`Wed Jul 25 2018 19:18:00 GMT${offset >= 0 ? '-' : '+'}${String(Math.abs(offset)).padStart(4, '0')}`), ); diff --git a/src/webviews/apps/shared/date.ts b/src/webviews/apps/shared/date.ts index 0b353f1a47c50..8dcbab27f86d4 100644 --- a/src/webviews/apps/shared/date.ts +++ b/src/webviews/apps/shared/date.ts @@ -1,16 +1,2 @@ 'use strict'; -import * as dayjs from 'dayjs'; -import advancedFormat from 'dayjs/plugin/advancedFormat'; -import relativeTime from 'dayjs/plugin/relativeTime'; - -dayjs.extend(advancedFormat); -dayjs.extend(relativeTime); - -export interface DateFormatter { - fromNow(): string; - format(format: string): string; -} - -export function getDateFormatter(date: Date): DateFormatter { - return dayjs.default(date); -} +export * from '../../../system/date'; diff --git a/src/webviews/apps/tsconfig.json b/src/webviews/apps/tsconfig.json index e5f2d0f89d036..4fae8511b7465 100644 --- a/src/webviews/apps/tsconfig.json +++ b/src/webviews/apps/tsconfig.json @@ -5,6 +5,6 @@ "lib": ["dom", "dom.iterable", "es2020"], "outDir": "../../" }, - "include": ["**/*", "../../config.ts", "../protocol.ts"], + "include": ["**/*", "../../../system/date.ts", "../../config.ts", "../protocol.ts"], "exclude": ["node_modules", "test"] } diff --git a/yarn.lock b/yarn.lock index 5033121df4aae..bfdd1ed53c9f4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1212,11 +1212,6 @@ data-uri-to-buffer@^3.0.1: resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-3.0.1.tgz#594b8973938c5bc2c33046535785341abc4f3636" integrity sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og== -dayjs@1.10.7: - version "1.10.7" - resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.10.7.tgz#2cf5f91add28116748440866a0a1d26f3a6ce468" - integrity sha512-P6twpd70BcPK34K26uJ1KT3wlhpuOAPoMwJzpsIWUxHZ7wpmbdZL/hQqBDfz7hGurYSa5PhzdhDHtt319hL3ig== - debug@^2.6.8, debug@^2.6.9: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" @@ -1762,14 +1757,13 @@ eslint-import-resolver-typescript@2.5.0: resolve "^1.20.0" tsconfig-paths "^3.9.0" -eslint-module-utils@^2.7.1: - version "2.7.1" - resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.7.1.tgz#b435001c9f8dd4ab7f6d0efcae4b9696d4c24b7c" - integrity sha512-fjoetBXQZq2tSTWZ9yWVl2KuFrTZZH3V+9iD1V1RfpDgxzJR+mPd/KZmMiA8gbPqdBzpNiEHOuT7IYEWxrH0zQ== +eslint-module-utils@^2.7.2: + version "2.7.2" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.7.2.tgz#1d0aa455dcf41052339b63cada8ab5fd57577129" + integrity sha512-zquepFnWCY2ISMFwD/DqzaM++H+7PDzOpUvotJWm/y1BAFt5R4oeULgdrTejKqLkz7MA/tgstsUMNYc7wNdTrg== dependencies: debug "^3.2.7" find-up "^2.1.0" - pkg-dir "^2.0.0" eslint-plugin-anti-trojan-source@1.1.0: version "1.1.0" @@ -1778,24 +1772,24 @@ eslint-plugin-anti-trojan-source@1.1.0: dependencies: anti-trojan-source "^1.3.1" -eslint-plugin-import@2.25.3: - version "2.25.3" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.25.3.tgz#a554b5f66e08fb4f6dc99221866e57cfff824766" - integrity sha512-RzAVbby+72IB3iOEL8clzPLzL3wpDrlwjsTBAQXgyp5SeTqqY+0bFubwuo+y/HLhNZcXV4XqTBO4LGsfyHIDXg== +eslint-plugin-import@2.25.4: + version "2.25.4" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.25.4.tgz#322f3f916a4e9e991ac7af32032c25ce313209f1" + integrity sha512-/KJBASVFxpu0xg1kIBn9AUa8hQVnszpwgE7Ld0lKAlx7Ie87yzEzCgSkekt+le/YVhiaosO4Y14GDAOc41nfxA== dependencies: array-includes "^3.1.4" array.prototype.flat "^1.2.5" debug "^2.6.9" doctrine "^2.1.0" eslint-import-resolver-node "^0.3.6" - eslint-module-utils "^2.7.1" + eslint-module-utils "^2.7.2" has "^1.0.3" is-core-module "^2.8.0" is-glob "^4.0.3" minimatch "^3.0.4" object.values "^1.1.5" resolve "^1.20.0" - tsconfig-paths "^3.11.0" + tsconfig-paths "^3.12.0" eslint-scope@5.1.1, eslint-scope@^5.1.1: version "5.1.1" @@ -3730,9 +3724,9 @@ picocolors@^1.0.0: integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3: - version "2.3.0" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972" - integrity sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw== + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== pify@^2.0.0, pify@^2.2.0, pify@^2.3.0: version "2.3.0" @@ -3761,13 +3755,6 @@ pinkie@^2.0.0: resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= -pkg-dir@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b" - integrity sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s= - dependencies: - find-up "^2.1.0" - pkg-dir@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" @@ -4673,7 +4660,7 @@ ts-loader@9.2.6: micromatch "^4.0.0" semver "^7.3.4" -tsconfig-paths@^3.11.0, tsconfig-paths@^3.9.0: +tsconfig-paths@^3.12.0, tsconfig-paths@^3.9.0: version "3.12.0" resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.12.0.tgz#19769aca6ee8f6a1a341e38c8fa45dd9fb18899b" integrity sha512-e5adrnOYT6zqVnWqZu7i/BQ3BnhzvGbjEjejFXO20lKIKpwTaupkCPgEfv4GZK1IBciJUEhYs3J3p75FdaTFVg==