From 6bed6ce2549e5ce1e96d6c721de3752a91343e64 Mon Sep 17 00:00:00 2001 From: EugeniyKiyashko Date: Tue, 18 Aug 2026 13:17:50 +0400 Subject: [PATCH 1/2] Core: remove m_ prefix from quid & dependency_injector files --- packages/devextreme/js/__internal/core/format_helper.ts | 2 +- packages/devextreme/js/__internal/core/{m_guid.ts => guid.ts} | 0 packages/devextreme/js/__internal/core/localization/core.ts | 2 +- packages/devextreme/js/__internal/core/localization/date.ts | 2 +- packages/devextreme/js/__internal/core/localization/message.ts | 2 +- packages/devextreme/js/__internal/core/localization/number.ts | 2 +- .../utils/{m_dependency_injector.ts => dependency_injector.ts} | 0 .../grids/new/card_view/content_view/content/card/card.test.tsx | 2 +- .../grids/new/card_view/content_view/content/card/card.tsx | 2 +- .../grids/new/grid_core/search/options.integration.test.ts | 2 +- .../devextreme/js/__internal/integration/knockout/validation.ts | 2 +- packages/devextreme/js/__internal/ui/color_box/color_view.ts | 2 +- packages/devextreme/js/__internal/ui/drop_down_button.ts | 2 +- packages/devextreme/js/common/guid.js | 2 +- packages/devextreme/js/core/utils/dependency_injector.js | 2 +- 15 files changed, 13 insertions(+), 13 deletions(-) rename packages/devextreme/js/__internal/core/{m_guid.ts => guid.ts} (100%) rename packages/devextreme/js/__internal/core/utils/{m_dependency_injector.ts => dependency_injector.ts} (100%) diff --git a/packages/devextreme/js/__internal/core/format_helper.ts b/packages/devextreme/js/__internal/core/format_helper.ts index 47a59ba385ba..a9a3dd4fc509 100644 --- a/packages/devextreme/js/__internal/core/format_helper.ts +++ b/packages/devextreme/js/__internal/core/format_helper.ts @@ -12,7 +12,7 @@ import { isPlainObject, isString, } from '@js/core/utils/type'; -import { injector as dependencyInjector } from '@ts/core/utils/m_dependency_injector'; +import { injector as dependencyInjector } from '@ts/core/utils/dependency_injector'; import { getGlobalFormatByDataType } from './global_format_config'; diff --git a/packages/devextreme/js/__internal/core/m_guid.ts b/packages/devextreme/js/__internal/core/guid.ts similarity index 100% rename from packages/devextreme/js/__internal/core/m_guid.ts rename to packages/devextreme/js/__internal/core/guid.ts diff --git a/packages/devextreme/js/__internal/core/localization/core.ts b/packages/devextreme/js/__internal/core/localization/core.ts index 4d247e1dd99a..4b02f628093e 100644 --- a/packages/devextreme/js/__internal/core/localization/core.ts +++ b/packages/devextreme/js/__internal/core/localization/core.ts @@ -1,6 +1,6 @@ import parentLocales from '@ts/core/localization/cldr-data/parent_locales'; import getParentLocale from '@ts/core/localization/parentLocale'; -import { injector as dependencyInjector } from '@ts/core/utils/m_dependency_injector'; +import { injector as dependencyInjector } from '@ts/core/utils/dependency_injector'; const DEFAULT_LOCALE = 'en'; diff --git a/packages/devextreme/js/__internal/core/localization/date.ts b/packages/devextreme/js/__internal/core/localization/date.ts index bf7002575276..2c643d6079fb 100644 --- a/packages/devextreme/js/__internal/core/localization/date.ts +++ b/packages/devextreme/js/__internal/core/localization/date.ts @@ -10,7 +10,7 @@ import { getFormatter as getLDMLDateFormatter } from '@ts/core/localization/ldml import { getParser as getLDMLDateParser } from '@ts/core/localization/ldml/date.parser'; import numberLocalization from '@ts/core/localization/number'; import errors from '@ts/core/m_errors'; -import { injector as dependencyInjector } from '@ts/core/utils/m_dependency_injector'; +import { injector as dependencyInjector } from '@ts/core/utils/dependency_injector'; import { each } from '@ts/core/utils/m_iterator'; import { isString } from '@ts/core/utils/m_type'; diff --git a/packages/devextreme/js/__internal/core/localization/message.ts b/packages/devextreme/js/__internal/core/localization/message.ts index ce6af1292db3..c0ae6d4317d6 100644 --- a/packages/devextreme/js/__internal/core/localization/message.ts +++ b/packages/devextreme/js/__internal/core/localization/message.ts @@ -1,6 +1,6 @@ import coreLocalization from '@ts/core/localization/core'; import { defaultMessages } from '@ts/core/localization/default_messages'; -import { injector as dependencyInjector } from '@ts/core/utils/m_dependency_injector'; +import { injector as dependencyInjector } from '@ts/core/utils/dependency_injector'; import { extend } from '@ts/core/utils/m_extend'; import { humanize } from '@ts/core/utils/m_inflector'; import { format as stringFormat } from '@ts/core/utils/m_string'; diff --git a/packages/devextreme/js/__internal/core/localization/number.ts b/packages/devextreme/js/__internal/core/localization/number.ts index 1a920b2fe10e..6cb5424e704c 100644 --- a/packages/devextreme/js/__internal/core/localization/number.ts +++ b/packages/devextreme/js/__internal/core/localization/number.ts @@ -7,8 +7,8 @@ import currencyLocalization from '@ts/core/localization/currency'; import intlNumberLocalization from '@ts/core/localization/intl/number'; import { getFormatter } from '@ts/core/localization/ldml/number'; import { toFixed } from '@ts/core/localization/utils'; +import { injector as dependencyInjector } from '@ts/core/utils/dependency_injector'; import { escapeRegExp } from '@ts/core/utils/m_common'; -import { injector as dependencyInjector } from '@ts/core/utils/m_dependency_injector'; import { each } from '@ts/core/utils/m_iterator'; import { isPlainObject } from '@ts/core/utils/m_type'; diff --git a/packages/devextreme/js/__internal/core/utils/m_dependency_injector.ts b/packages/devextreme/js/__internal/core/utils/dependency_injector.ts similarity index 100% rename from packages/devextreme/js/__internal/core/utils/m_dependency_injector.ts rename to packages/devextreme/js/__internal/core/utils/dependency_injector.ts diff --git a/packages/devextreme/js/__internal/grids/new/card_view/content_view/content/card/card.test.tsx b/packages/devextreme/js/__internal/grids/new/card_view/content_view/content/card/card.test.tsx index 449eb3fe9e2e..b730348db7ec 100644 --- a/packages/devextreme/js/__internal/grids/new/card_view/content_view/content/card/card.test.tsx +++ b/packages/devextreme/js/__internal/grids/new/card_view/content_view/content/card/card.test.tsx @@ -2,7 +2,7 @@ import { afterEach, beforeEach, describe, expect, it, jest, } from '@jest/globals'; import { compileGetter } from '@js/common/data'; -import { Guid } from '@ts/core/m_guid'; +import { Guid } from '@ts/core/guid'; import { render } from 'inferno'; import { Card } from './card'; diff --git a/packages/devextreme/js/__internal/grids/new/card_view/content_view/content/card/card.tsx b/packages/devextreme/js/__internal/grids/new/card_view/content_view/content/card/card.tsx index 1dbfc85de48a..0e5364fe2815 100644 --- a/packages/devextreme/js/__internal/grids/new/card_view/content_view/content/card/card.tsx +++ b/packages/devextreme/js/__internal/grids/new/card_view/content_view/content/card/card.tsx @@ -7,7 +7,7 @@ import { getPublicElement } from '@js/core/element'; import $ from '@js/core/renderer'; import { off, on } from '@js/events/index'; import type * as dxToolbar from '@js/ui/toolbar'; -import { Guid } from '@ts/core/m_guid'; +import { Guid } from '@ts/core/guid'; import { combineClasses } from '@ts/core/utils/combine_classes'; import type { Position } from '@ts/grids/new/grid_core/accessibility/types'; import { getCardDescriptiveLabel, getCardRoleDescription, getCardStateDescription } from '@ts/grids/new/grid_core/accessibility/utils'; diff --git a/packages/devextreme/js/__internal/grids/new/grid_core/search/options.integration.test.ts b/packages/devextreme/js/__internal/grids/new/grid_core/search/options.integration.test.ts index c1665b797abf..b725b3deafd6 100644 --- a/packages/devextreme/js/__internal/grids/new/grid_core/search/options.integration.test.ts +++ b/packages/devextreme/js/__internal/grids/new/grid_core/search/options.integration.test.ts @@ -5,7 +5,7 @@ import { describe, expect, it, jest, } from '@jest/globals'; -import { Guid } from '@ts/core/m_guid'; +import { Guid } from '@ts/core/guid'; import CardView from '@ts/grids/new/card_view/widget'; import type { Options as GridCoreOptions } from '@ts/grids/new/grid_core/options'; import { rerender } from 'inferno'; diff --git a/packages/devextreme/js/__internal/integration/knockout/validation.ts b/packages/devextreme/js/__internal/integration/knockout/validation.ts index e6d503f3fafd..945c78a188ed 100644 --- a/packages/devextreme/js/__internal/integration/knockout/validation.ts +++ b/packages/devextreme/js/__internal/integration/knockout/validation.ts @@ -1,6 +1,6 @@ +import { Guid } from '@ts/core/guid'; import Class from '@ts/core/m_class'; import { EventsStrategy } from '@ts/core/m_events_strategy'; -import { Guid } from '@ts/core/m_guid'; import { Deferred } from '@ts/core/utils/m_deferred'; import { extend } from '@ts/core/utils/m_extend'; import { each, map } from '@ts/core/utils/m_iterator'; diff --git a/packages/devextreme/js/__internal/ui/color_box/color_view.ts b/packages/devextreme/js/__internal/ui/color_box/color_view.ts index 70a01dd14860..3da63bb6443b 100644 --- a/packages/devextreme/js/__internal/ui/color_box/color_view.ts +++ b/packages/devextreme/js/__internal/ui/color_box/color_view.ts @@ -5,9 +5,9 @@ import type { dxElementWrapper } from '@js/core/renderer'; import $ from '@js/core/renderer'; import { Color, type ColorInstance } from '@ts/color'; import { locate, move } from '@ts/common/core/animation/translator'; +import { Guid } from '@ts/core/guid'; import messageLocalization from '@ts/core/localization/message'; import devices from '@ts/core/m_devices'; -import { Guid } from '@ts/core/m_guid'; import { extend } from '@ts/core/utils/m_extend'; import { getHeight, getOuterHeight, getWidth } from '@ts/core/utils/m_size'; import type { OptionChanged } from '@ts/core/widget/types'; diff --git a/packages/devextreme/js/__internal/ui/drop_down_button.ts b/packages/devextreme/js/__internal/ui/drop_down_button.ts index 7cdf29ffe916..a8d4374b28c6 100644 --- a/packages/devextreme/js/__internal/ui/drop_down_button.ts +++ b/packages/devextreme/js/__internal/ui/drop_down_button.ts @@ -18,9 +18,9 @@ import ButtonGroup from '@js/ui/button_group'; import type { Item, Properties } from '@js/ui/drop_down_button'; import type { ItemClickEvent } from '@js/ui/list'; import type { PositionAlignment } from '@js/ui/popup'; +import { Guid } from '@ts/core/guid'; import messageLocalization from '@ts/core/localization/message'; import { getPublicElement } from '@ts/core/m_element'; -import { Guid } from '@ts/core/m_guid'; import { FunctionTemplate } from '@ts/core/templates/m_function_template'; import { ensureDefined } from '@ts/core/utils/m_common'; import { isDefined, isObject, isPlainObject } from '@ts/core/utils/m_type'; diff --git a/packages/devextreme/js/common/guid.js b/packages/devextreme/js/common/guid.js index 2a2ab6ecb7c7..d45af0848ede 100644 --- a/packages/devextreme/js/common/guid.js +++ b/packages/devextreme/js/common/guid.js @@ -7,5 +7,5 @@ * @publicName ctor(value) * @param1 value:string */ -import { Guid } from '../__internal/core/m_guid'; +import { Guid } from '../__internal/core/guid'; export default Guid; diff --git a/packages/devextreme/js/core/utils/dependency_injector.js b/packages/devextreme/js/core/utils/dependency_injector.js index d74c4cb93691..b371e1d15ba5 100644 --- a/packages/devextreme/js/core/utils/dependency_injector.js +++ b/packages/devextreme/js/core/utils/dependency_injector.js @@ -1,3 +1,3 @@ // deprecated -import { injector } from '../../__internal/core/utils/m_dependency_injector'; +import { injector } from '../../__internal/core/utils/dependency_injector'; export default injector; From 8ae28d2a7f7d07da7092f571f829d69b734d8213 Mon Sep 17 00:00:00 2001 From: EugeniyKiyashko Date: Tue, 18 Aug 2026 13:31:15 +0400 Subject: [PATCH 2/2] Core: fix eslint/ts errors after rename quid & dependency_injector --- .../devextreme/js/__internal/core/guid.ts | 62 +++++----- .../js/__internal/core/localization/core.ts | 23 ++-- .../__internal/core/localization/currency.ts | 6 +- .../js/__internal/core/localization/date.ts | 15 +-- .../core/localization/default_date_names.ts | 2 +- .../core/localization/globalize/currency.ts | 25 ++-- .../core/localization/globalize/date.ts | 6 +- .../core/localization/globalize/number.ts | 4 +- .../__internal/core/localization/intl/date.ts | 10 +- .../core/localization/intl/number.ts | 9 +- .../core/localization/ldml/date.formatter.ts | 90 ++++++++------ .../js/__internal/core/localization/number.ts | 30 +++-- .../core/utils/dependency_injector.ts | 115 ++++++++++++++---- .../js/__internal/core/utils/m_data.ts | 3 +- .../core/utils/m_variable_wrapper.ts | 11 +- .../__internal/events/core/m_events_engine.ts | 32 ++++- .../content_view/content/card/card.tsx | 4 +- .../__internal/ui/date_box/date_box.mask.ts | 9 +- .../ui/number_box/m_number_box.mask.ts | 4 +- .../js/__internal/ui/slider/m_slider.ts | 4 +- .../js/__internal/ui/validation_engine.ts | 4 +- 21 files changed, 302 insertions(+), 166 deletions(-) diff --git a/packages/devextreme/js/__internal/core/guid.ts b/packages/devextreme/js/__internal/core/guid.ts index 13e922b3d1a0..0f582e1d16c0 100644 --- a/packages/devextreme/js/__internal/core/guid.ts +++ b/packages/devextreme/js/__internal/core/guid.ts @@ -1,47 +1,47 @@ -import Class from '@js/core/class'; +export class Guid { + private readonly _value: string; -const Guid = Class.inherit({ - ctor: function (value) { - if (value) { - value = String(value); - } - this._value = this._normalize(value || this._generate()); - }, + constructor(value?: string) { + const initialValue = value ? String(value) : ''; + + this._value = this._normalize(initialValue || this._generate()); + } - _normalize: function (value) { - value = value.replace(/[^a-f0-9]/ig, '').toLowerCase(); - while (value.length < 32) { - value += '0'; + public _normalize(value: string): string { + let normalizedValue = value.replace(/[^a-f0-9]/ig, '').toLowerCase(); + + while (normalizedValue.length < 32) { + normalizedValue += '0'; } + return [ - value.substr(0, 8), - value.substr(8, 4), - value.substr(12, 4), - value.substr(16, 4), - value.substr(20, 12), + normalizedValue.substr(0, 8), + normalizedValue.substr(8, 4), + normalizedValue.substr(12, 4), + normalizedValue.substr(16, 4), + normalizedValue.substr(20, 12), ].join('-'); - }, + } - _generate: function () { + private _generate(): string { let value = ''; - for (let i = 0; i < 32; i++) { + + for (let i = 0; i < 32; i += 1) { value += Math.round(Math.random() * 15).toString(16); } + return value; - }, + } - toString: function () { + public toString(): string { return this._value; - }, + } - valueOf: function () { + public valueOf(): string { return this._value; - }, + } - toJSON: function () { + public toJSON(): string { return this._value; - }, - -}); - -export { Guid }; + } +} diff --git a/packages/devextreme/js/__internal/core/localization/core.ts b/packages/devextreme/js/__internal/core/localization/core.ts index 4b02f628093e..726a34befea6 100644 --- a/packages/devextreme/js/__internal/core/localization/core.ts +++ b/packages/devextreme/js/__internal/core/localization/core.ts @@ -4,23 +4,32 @@ import { injector as dependencyInjector } from '@ts/core/utils/dependency_inject const DEFAULT_LOCALE = 'en'; +interface LocaleAccessor { + (): string; + (locale: string): void; +} + export default dependencyInjector({ - locale: (() => { + locale: ((): LocaleAccessor => { let currentLocale = DEFAULT_LOCALE; - // eslint-disable-next-line @typescript-eslint/no-invalid-void-type,consistent-return - return (locale?: string): string | void => { + function localeAccessor(): string; + function localeAccessor(locale: string): void; + // eslint-disable-next-line consistent-return + function localeAccessor(locale?: string): string | void { if (!locale) { return currentLocale; } currentLocale = locale; - }; + } + + return localeAccessor; })(), - getValueByClosestLocale( - getter: (locale: string) => string | number | undefined, - ): string | number | undefined { + getValueByClosestLocale( + getter: (locale: string) => TValue | undefined, + ): TValue | undefined { let locale: string = this.locale(); let value = getter(locale); let isRootLocale = false; diff --git a/packages/devextreme/js/__internal/core/localization/currency.ts b/packages/devextreme/js/__internal/core/localization/currency.ts index 643aac6f0aa8..2f33ac20a8bc 100644 --- a/packages/devextreme/js/__internal/core/localization/currency.ts +++ b/packages/devextreme/js/__internal/core/localization/currency.ts @@ -16,10 +16,12 @@ export default { // eslint-disable-next-line @typescript-eslint/no-unsafe-return return this.callBase.apply(this, [value, format, formatConfig]); }, - getCurrencySymbol(): { symbol: string } { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + getCurrencySymbol(currency?: string): { symbol: string } { return { symbol: '$' }; }, - getOpenXmlCurrencyFormat(): string { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + getOpenXmlCurrencyFormat(currency?: string): string | undefined { return '$#,##0{0}_);\\($#,##0{0}\\)'; }, }; diff --git a/packages/devextreme/js/__internal/core/localization/date.ts b/packages/devextreme/js/__internal/core/localization/date.ts index 2c643d6079fb..9487b2be105c 100644 --- a/packages/devextreme/js/__internal/core/localization/date.ts +++ b/packages/devextreme/js/__internal/core/localization/date.ts @@ -85,7 +85,6 @@ const dateLocalization = dependencyInjector({ (presetOverride as string).toLowerCase() ] || presetOverride as string; - // eslint-disable-next-line @typescript-eslint/no-unsafe-return return numberLocalization.convertDigits( getLDMLDateFormatter(pattern, this)(date), ); @@ -114,16 +113,20 @@ const dateLocalization = dependencyInjector({ return result; }, - getMonthNames(format: BaseFormat): string[] { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + getMonthNames(format: Format, type?: string): string[] { return defaultDateNames.getMonthNames(format); }, - getDayNames(format: BaseFormat): string[] { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + getDayNames(format: Format, type?: string): string[] { return defaultDateNames.getDayNames(format); }, - getQuarterNames(format: BaseFormat): string[] { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + getQuarterNames(format: Format, type?: string): string[] { return defaultDateNames.getQuarterNames(format); }, - getPeriodNames(format: BaseFormat): string[] { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + getPeriodNames(format?: Format, type?: string): string[] { return defaultDateNames.getPeriodNames(format); }, getTimeSeparator(): string { @@ -175,7 +178,6 @@ const dateLocalization = dependencyInjector({ // eslint-disable-next-line no-param-reassign format = (FORMATS_TO_PATTERN_MAP[(format as string).toLowerCase()] || format) as string; - // eslint-disable-next-line @typescript-eslint/no-unsafe-return return numberLocalization.convertDigits(getLDMLDateFormatter(format, this)(date)); } } @@ -216,7 +218,6 @@ const dateLocalization = dependencyInjector({ // eslint-disable-next-line @typescript-eslint/no-shadow const text: string = that.format(value, format); - // eslint-disable-next-line @typescript-eslint/no-unsafe-return return numberLocalization.convertDigits(text, true); }; try { diff --git a/packages/devextreme/js/__internal/core/localization/default_date_names.ts b/packages/devextreme/js/__internal/core/localization/default_date_names.ts index 622f69033428..4e47a67fe195 100644 --- a/packages/devextreme/js/__internal/core/localization/default_date_names.ts +++ b/packages/devextreme/js/__internal/core/localization/default_date_names.ts @@ -30,7 +30,7 @@ export default { return QUARTERS; }, // eslint-disable-next-line @typescript-eslint/no-unused-vars - getPeriodNames(_format: Format): string[] { + getPeriodNames(_format?: Format): string[] { return PERIODS; }, }; diff --git a/packages/devextreme/js/__internal/core/localization/globalize/currency.ts b/packages/devextreme/js/__internal/core/localization/globalize/currency.ts index 7364f4b98dbe..677462c74845 100644 --- a/packages/devextreme/js/__internal/core/localization/globalize/currency.ts +++ b/packages/devextreme/js/__internal/core/localization/globalize/currency.ts @@ -4,7 +4,7 @@ import '@ts/core/localization/currency'; import 'globalize/currency'; import config from '@js/core/config'; -import type { FormatConfig, NormalizedConfig } from '@ts/core/localization/number'; +import type { FormatConfig, LocalizationFormat, NormalizedConfig } from '@ts/core/localization/number'; import numberLocalization from '@ts/core/localization/number'; import openXmlCurrencyFormat from '@ts/core/localization/open_xml_currency_format'; // eslint-disable-next-line import/no-extraneous-dependencies @@ -79,30 +79,29 @@ if (Globalize?.formatCurrency) { }, format( value: string | number, - format: number | string | FormatConfig | Function | undefined, + format?: LocalizationFormat, ): string | number { if (typeof value !== 'number') { return value; } - // eslint-disable-next-line no-param-reassign - format = this._normalizeFormat(format) as FormatConfig; + const normalizedFormat = this._normalizeFormat(format) as FormatConfig; - if (format) { - if (format.currency === 'default') { - format.currency = config().defaultCurrency; + if (normalizedFormat) { + if (normalizedFormat.currency === 'default') { + normalizedFormat.currency = config().defaultCurrency; } - if (format.type === 'currency') { + if (normalizedFormat.type === 'currency') { // eslint-disable-next-line @typescript-eslint/no-unsafe-return - return this._formatNumber(value, this._parseNumberFormatString('currency'), format); - } if (!format.type && format.currency) { - return getFormatter(format.currency, format)(value); + return this._formatNumber(value, this._parseNumberFormatString('currency'), normalizedFormat); + } if (!normalizedFormat.type && normalizedFormat.currency) { + return getFormatter(normalizedFormat.currency, normalizedFormat)(value); } } // eslint-disable-next-line @typescript-eslint/no-unsafe-return - return this.callBase.apply(this, [value, format]); + return this.callBase.apply(this, [value, normalizedFormat]); }, getCurrencySymbol(currency?: string): { symbol: string } { if (!currency) { @@ -113,7 +112,7 @@ if (Globalize?.formatCurrency) { // eslint-disable-next-line @typescript-eslint/no-unsafe-return return Globalize.cldr.main(`numbers/currencies/${currency}`); }, - getOpenXmlCurrencyFormat(currency: string): string | undefined { + getOpenXmlCurrencyFormat(currency?: string): string | undefined { const currencySymbol = this.getCurrencySymbol(currency).symbol; const accountingFormat = Globalize.cldr.main('numbers/currencyFormats-numberSystem-latn').accounting; diff --git a/packages/devextreme/js/__internal/core/localization/globalize/date.ts b/packages/devextreme/js/__internal/core/localization/globalize/date.ts index 56be41d04666..0ba0261c70bc 100644 --- a/packages/devextreme/js/__internal/core/localization/globalize/date.ts +++ b/packages/devextreme/js/__internal/core/localization/globalize/date.ts @@ -127,7 +127,7 @@ if (Globalize?.formatDate) { return Globalize.locale().main(`dates/calendars/gregorian/${path}`); }, - getPeriodNames(format: Format, type: string): string[] { + getPeriodNames(format?: Format, type?: string): string[] { // eslint-disable-next-line no-param-reassign format = format || 'wide'; // eslint-disable-next-line no-param-reassign @@ -137,7 +137,7 @@ if (Globalize?.formatDate) { return [json.am, json.pm]; }, - getMonthNames(format: Format, type: string): string[] { + getMonthNames(format: Format, type?: string): string[] { const months: Record = Globalize.locale().main(`dates/calendars/gregorian/months/${type === 'format' ? type : 'stand-alone'}/${format || 'wide'}`); // eslint-disable-next-line @typescript-eslint/no-unsafe-return @@ -228,7 +228,7 @@ if (Globalize?.formatDate) { return this.removeRtlMarks(formatter(date)); }, - parse(text: string, format: FormatObject | DateParser | string): Date | null | undefined { + parse(text: string, format?: FormatObject | DateParser | string): Date | null | undefined { if (!text) { return undefined; } diff --git a/packages/devextreme/js/__internal/core/localization/globalize/number.ts b/packages/devextreme/js/__internal/core/localization/globalize/number.ts index 3c4e99be24f1..0326f42c54c8 100644 --- a/packages/devextreme/js/__internal/core/localization/globalize/number.ts +++ b/packages/devextreme/js/__internal/core/localization/globalize/number.ts @@ -99,7 +99,7 @@ if (Globalize?.formatNumber) { format( value: string | number, - format: LocalizationFormat, + format?: LocalizationFormat, ): string { if (typeof value !== 'number') { return value; @@ -120,7 +120,7 @@ if (Globalize?.formatNumber) { parse( text: string, - format: FormatConfig | string, + format?: FormatConfig | string, ): number | null | undefined { if (!text) { return undefined; diff --git a/packages/devextreme/js/__internal/core/localization/intl/date.ts b/packages/devextreme/js/__internal/core/localization/intl/date.ts index b2ae3bf9313b..4964694a7146 100644 --- a/packages/devextreme/js/__internal/core/localization/intl/date.ts +++ b/packages/devextreme/js/__internal/core/localization/intl/date.ts @@ -169,7 +169,7 @@ export default { engine(): string { return 'intl'; }, - getMonthNames(format: Format, type: string): string[] { + getMonthNames(format: Format, type?: string): string[] { // eslint-disable-next-line @typescript-eslint/no-shadow const intlFormats: Record, Intl.DateTimeFormatOptions['month']> = { wide: 'long', @@ -178,14 +178,12 @@ export default { }; const monthFormat = intlFormats[format || 'wide']; - - // eslint-disable-next-line no-param-reassign - type = type === 'format' ? type : 'standalone'; + const nameType = type === 'format' ? type : 'standalone'; return Array.from( { length: 12 }, // eslint-disable-next-line @typescript-eslint/no-unsafe-return - (_, monthIndex): string => monthNameStrategies[type](monthIndex, monthFormat), + (_, monthIndex): string => monthNameStrategies[nameType](monthIndex, monthFormat), ); }, @@ -267,7 +265,7 @@ export default { return getIntlFormatter(format)(date); }, - parse(dateString: string, format: FormatObject | string): Date | null | undefined { + parse(dateString: string, format?: FormatObject | string): Date | null | undefined { // eslint-disable-next-line @typescript-eslint/init-declarations let formatter: DateFormatter | undefined; diff --git a/packages/devextreme/js/__internal/core/localization/intl/number.ts b/packages/devextreme/js/__internal/core/localization/intl/number.ts index 630f0ffc7275..afc160434d02 100644 --- a/packages/devextreme/js/__internal/core/localization/intl/number.ts +++ b/packages/devextreme/js/__internal/core/localization/intl/number.ts @@ -101,7 +101,7 @@ export default { }, format( value: string | number, - format: LocalizationFormat, + format?: LocalizationFormat, ): string { if (typeof value !== 'number') { return value; @@ -149,10 +149,9 @@ export default { }; }, - getCurrencySymbol(currency: string): { symbol: string } { + getCurrencySymbol(currency?: string): { symbol: string } { if (!currency) { - // @ts-expect-error - // eslint-disable-next-line + // eslint-disable-next-line no-param-reassign currency = dxConfig().defaultCurrency; } @@ -161,7 +160,7 @@ export default { symbol: symbolInfo.symbol, }; }, - getOpenXmlCurrencyFormat(currency: string): string | undefined { + getOpenXmlCurrencyFormat(currency?: string): string | undefined { const targetCurrency = currency || dxConfig().defaultCurrency; const currencySymbol: string = this._getCurrencySymbolInfo(targetCurrency).symbol; const closestAccountingFormat: string | undefined = localizationCoreUtils diff --git a/packages/devextreme/js/__internal/core/localization/ldml/date.formatter.ts b/packages/devextreme/js/__internal/core/localization/ldml/date.formatter.ts index b845cfa57270..58fde9bb16b1 100644 --- a/packages/devextreme/js/__internal/core/localization/ldml/date.formatter.ts +++ b/packages/devextreme/js/__internal/core/localization/ldml/date.formatter.ts @@ -101,54 +101,64 @@ const LDML_FORMATTERS = { }, }; -export const getFormatter = ( +export function getFormatter( + format: string, + dateParts: LdlmDateLocalization, +): (date: Date | null) => string; +export function getFormatter( format: string | undefined, dateParts: LdlmDateLocalization, -) => (date: Date | null): Date | string | null => { - // eslint-disable-next-line @typescript-eslint/init-declarations - let charIndex: number; - // eslint-disable-next-line @typescript-eslint/init-declarations - let formatter: typeof LDML_FORMATTERS[keyof typeof LDML_FORMATTERS]; - // eslint-disable-next-line @typescript-eslint/init-declarations - let char: string; - let charCount = 0; - const separator = '\''; - let isEscaping = false; +): (date: Date | null) => Date | string | null; +export function getFormatter( + format: string | undefined, + dateParts: LdlmDateLocalization, +): (date: Date | null) => Date | string | null { + return (date: Date | null): Date | string | null => { // eslint-disable-next-line @typescript-eslint/init-declarations - let isCurrentCharEqualsNext: boolean; - let result = ''; + let charIndex: number; + // eslint-disable-next-line @typescript-eslint/init-declarations + let formatter: typeof LDML_FORMATTERS[keyof typeof LDML_FORMATTERS]; + // eslint-disable-next-line @typescript-eslint/init-declarations + let char: string; + let charCount = 0; + const separator = '\''; + let isEscaping = false; + // eslint-disable-next-line @typescript-eslint/init-declarations + let isCurrentCharEqualsNext: boolean; + let result = ''; - if (!date) { - return null; - } + if (!date) { + return null; + } - if (!format) { - return date; - } + if (!format) { + return date; + } - const useUtc = format.endsWith('Z') || format.endsWith('\'Z\''); + const useUtc = format.endsWith('Z') || format.endsWith('\'Z\''); - for (charIndex = 0; charIndex < format.length; charIndex += 1) { - char = format[charIndex]; - formatter = LDML_FORMATTERS[char]; - isCurrentCharEqualsNext = char === format[charIndex + 1]; - charCount += 1; + for (charIndex = 0; charIndex < format.length; charIndex += 1) { + char = format[charIndex]; + formatter = LDML_FORMATTERS[char]; + isCurrentCharEqualsNext = char === format[charIndex + 1]; + charCount += 1; - if (!isCurrentCharEqualsNext) { - if (formatter && !isEscaping) { - result += formatter(date, charCount, useUtc, dateParts); + if (!isCurrentCharEqualsNext) { + if (formatter && !isEscaping) { + result += formatter(date, charCount, useUtc, dateParts); + } + charCount = 0; } - charCount = 0; - } - if (char === separator && !isCurrentCharEqualsNext) { - isEscaping = !isEscaping; - } else if (isEscaping || !formatter) { - result += char; - } - if (char === separator && isCurrentCharEqualsNext) { - charIndex += 1; + if (char === separator && !isCurrentCharEqualsNext) { + isEscaping = !isEscaping; + } else if (isEscaping || !formatter) { + result += char; + } + if (char === separator && isCurrentCharEqualsNext) { + charIndex += 1; + } } - } - return result; -}; + return result; + }; +} diff --git a/packages/devextreme/js/__internal/core/localization/number.ts b/packages/devextreme/js/__internal/core/localization/number.ts index 6cb5424e704c..53631e00f316 100644 --- a/packages/devextreme/js/__internal/core/localization/number.ts +++ b/packages/devextreme/js/__internal/core/localization/number.ts @@ -62,8 +62,8 @@ export interface FormatterConfig { unlimitedIntegerDigits?: boolean; } -const numberLocalization = dependencyInjector({ - engine() { +const numberLocalizationBase = { + engine(): string { return 'base'; }, numericFormats: NUMERIC_FORMATS, @@ -267,7 +267,10 @@ const numberLocalization = dependencyInjector({ return this.format(1.2, { type: 'fixedPoint', precision: 1 })[1] as string; }, - convertDigits(value: string | number, toStandard?: boolean): string | number { + convertDigits( + value: TValue, + toStandard?: boolean, + ): TValue { const digits: string = this.format(90, 'decimal'); if (typeof value !== 'string' || digits[1] === '0') { @@ -280,7 +283,7 @@ const numberLocalization = dependencyInjector({ const regExp = new RegExp(`[${fromFirstDigit}-${fromLastDigit}]`, 'g'); // eslint-disable-next-line @stylistic/max-len - return value.replace(regExp, (char) => String.fromCharCode(char.charCodeAt(0) + (toFirstDigit.charCodeAt(0) - fromFirstDigit.charCodeAt(0)))); + return value.replace(regExp, (char) => String.fromCharCode(char.charCodeAt(0) + (toFirstDigit.charCodeAt(0) - fromFirstDigit.charCodeAt(0)))) as TValue; }, getNegativeEtalonRegExp(format: FormatConfig | string): RegExp { @@ -298,7 +301,7 @@ const numberLocalization = dependencyInjector({ return new RegExp(negativeEtalon, 'g'); }, - getSign(text: string, format: FormatConfig | string): 1 | -1 { + getSign(text: string, format?: FormatConfig | string): 1 | -1 { if (!format) { if (text.replace(/[^0-9-]/g, '').startsWith('-')) { return -1; @@ -357,7 +360,7 @@ const numberLocalization = dependencyInjector({ return this._formatNumber(value, numberConfig, format) as string; }, - parse(text: string, format: FormatConfig | string): number | null | undefined { + parse(text: string, format?: FormatConfig | string): number | null | undefined { if (!text) { return undefined; } @@ -437,7 +440,20 @@ const numberLocalization = dependencyInjector({ } return result; }, -}); +}; + +type NumberLocalizationContract = Omit + & typeof currencyLocalization + & { + format: { + (value: number, format?: LocalizationFormat): string; + (value: string | number, format?: LocalizationFormat): string | number; + }; + }; + +const numberLocalization = dependencyInjector( + numberLocalizationBase as NumberLocalizationContract, +); numberLocalization.inject(currencyLocalization); diff --git a/packages/devextreme/js/__internal/core/utils/dependency_injector.ts b/packages/devextreme/js/__internal/core/utils/dependency_injector.ts index acda838cd10d..39d04c38ee6f 100644 --- a/packages/devextreme/js/__internal/core/utils/dependency_injector.ts +++ b/packages/devextreme/js/__internal/core/utils/dependency_injector.ts @@ -1,48 +1,115 @@ -/* eslint-disable prefer-arrow-callback */ -/* eslint-disable func-names */ -import Class from '@js/core/class'; import { extend } from '@js/core/utils/extend'; import { each } from '@js/core/utils/iterator'; import { isFunction } from '@js/core/utils/type'; -function injector(object) { - const BaseClass = Class.inherit(object); - let InjectedClass = BaseClass; - let instance = new InjectedClass(object); - const initialFields = {}; +type InjectionStore = Record; - const injectFields = function (injectionObject, initial?) { - each(injectionObject, function (key) { +type InjectedMethod = (...args: unknown[]) => unknown; + +interface CallBaseHolder { + callBase?: unknown; +} + +export type Injection = { + [K in keyof T]?: T[K] extends (...args: infer TArgs) => infer TResult + ? (this: Injectable & { callBase: T[K] }, ...args: TArgs) => TResult + : T[K]; +} & { + // Invoked once when the injection is applied (and again on every later inject call + // while this injection stays the topmost one that declares a ctor). + ctor?: (this: T) => void; +}; + +export type Injectable = T & { + inject: (injectionObject: Injection) => void; + resetInjection: () => void; +}; + +function isInjectedMethod(value: unknown): value is InjectedMethod { + return isFunction(value); +} + +function wrapOverridden( + base: InjectionStore, + methodName: string, + method: InjectedMethod, +): InjectedMethod { + return function overriddenMethod(this: CallBaseHolder, ...args: unknown[]): unknown { + const prevCallBase = this.callBase; + + this.callBase = base[methodName]; + + try { + return method.apply(this, args); + } finally { + this.callBase = prevCallBase; + } + }; +} + +function injector(object: T): Injectable { + const facade = object as InjectionStore; + const initialFields: InjectionStore = {}; + const baseInstance: InjectionStore = {}; + + each(facade, (key: string): void => { + baseInstance[key] = facade[key]; + }); + + let instance = baseInstance; + + const invokeConstructor = (...args: unknown[]): void => { + const { ctor } = instance; + + if (isInjectedMethod(ctor)) { + ctor.apply(instance, args); + } + }; + + const injectFields = (injectionObject: object, initial?: boolean): void => { + each(injectionObject, (key: string): void => { if (isFunction(instance[key])) { - if (initial || !object[key]) { - object[key] = function () { - return instance[key].apply(object, arguments); + if (initial || !facade[key]) { + facade[key] = (...args: unknown[]): unknown => { + const method = instance[key] as InjectedMethod; + + return method.apply(facade, args); }; } } else { if (initial) { - initialFields[key] = object[key]; + initialFields[key] = facade[key]; } - object[key] = instance[key]; + facade[key] = instance[key]; } }); }; - injectFields(object, true); + invokeConstructor(object); + injectFields(facade, true); + + facade.inject = (injectionObject: Injection): void => { + const overriddenInstance: InjectionStore = Object.create(instance); + + each(injectionObject, (key: string, member: unknown): void => { + overriddenInstance[key] = isFunction(instance[key]) && isInjectedMethod(member) + ? wrapOverridden(instance, key, member) + : member; + }); + + instance = overriddenInstance; - object.inject = function (injectionObject) { - InjectedClass = InjectedClass.inherit(injectionObject); - instance = new InjectedClass(); + invokeConstructor(); injectFields(injectionObject); }; - object.resetInjection = function () { - extend(object, initialFields); - InjectedClass = BaseClass; - instance = new BaseClass(); + facade.resetInjection = (): void => { + extend(facade, initialFields); + instance = baseInstance; + invokeConstructor(); }; - return object; + return object as Injectable; } export { injector }; diff --git a/packages/devextreme/js/__internal/core/utils/m_data.ts b/packages/devextreme/js/__internal/core/utils/m_data.ts index c95ba7dc3544..bd80b11beaf0 100644 --- a/packages/devextreme/js/__internal/core/utils/m_data.ts +++ b/packages/devextreme/js/__internal/core/utils/m_data.ts @@ -1,5 +1,6 @@ import Class from '@js/core/class'; import errors from '@js/core/errors'; +import Guid from '@js/core/guid'; import { each } from '@js/core/utils/iterator'; import { deepExtendArraySafe } from '@js/core/utils/object'; import { @@ -240,7 +241,7 @@ export const toComparable = function (value, caseSensitive?, options: any = {}) const collatorSensitivity = options?.collatorOptions?.sensitivity; - if (value && value instanceof Class && value.valueOf) { + if (value && (value instanceof Class || value instanceof Guid) && value.valueOf) { value = value.valueOf(); } else if (typeof value === 'string' && (collatorSensitivity === 'base' || collatorSensitivity === 'case')) { const REMOVE_DIACRITICAL_MARKS_REGEXP = /[\u0300-\u036f]/g; diff --git a/packages/devextreme/js/__internal/core/utils/m_variable_wrapper.ts b/packages/devextreme/js/__internal/core/utils/m_variable_wrapper.ts index b1c82d0e17e3..c4e2579acff6 100644 --- a/packages/devextreme/js/__internal/core/utils/m_variable_wrapper.ts +++ b/packages/devextreme/js/__internal/core/utils/m_variable_wrapper.ts @@ -1,8 +1,15 @@ -/* eslint-disable object-shorthand */ import { logger } from '@js/core/utils/console'; import dependencyInjector from '@js/core/utils/dependency_injector'; -const variableWrapper = dependencyInjector({ +interface VariableWrapper { + isWrapped: (value: any) => boolean; + isWritableWrapped: (value: any) => boolean; + wrap: (value: any) => any; + unwrap: (value: any) => any; + assign: (variable: any, value: any) => void; +} + +const variableWrapper = dependencyInjector({ isWrapped: function () { return false; }, diff --git a/packages/devextreme/js/__internal/events/core/m_events_engine.ts b/packages/devextreme/js/__internal/events/core/m_events_engine.ts index b11f4ce2a4d4..b6343211d372 100644 --- a/packages/devextreme/js/__internal/events/core/m_events_engine.ts +++ b/packages/devextreme/js/__internal/events/core/m_events_engine.ts @@ -11,6 +11,7 @@ import { isFunction, isObject, isString, isWindow, } from '@js/core/utils/type'; import { getWindow, hasWindow } from '@js/core/utils/window'; +import type { Injection } from '@ts/core/utils/dependency_injector'; import { EMPTY_EVENT_NAME, EVENT_PROPERTIES, @@ -29,6 +30,29 @@ const elementDataMap = new WeakMap(); let guid = 0; let skipEvent; +type EventsEngineMethod = (...args: any[]) => void; + +interface EventFactory { + prototype: any; + (src?: any, config?: any): any; + new (src?: any, config?: any): any; +} + +interface EventsEngine { + on: EventsEngineMethod; + one: EventsEngineMethod; + off: EventsEngineMethod; + trigger: EventsEngineMethod; + triggerHandler: EventsEngineMethod; + Event: EventFactory; + set: (engine: Injection) => void; + subscribeGlobal: EventsEngineMethod; + forcePassiveFalseEventNames: typeof forcePassiveFalseEventNames; + passiveEventHandlersSupported: () => boolean; + elementDataMap: typeof elementDataMap; + detectPassiveEventHandlersSupport: () => boolean; +} + const special = (function () { const specialData = {}; @@ -109,7 +133,7 @@ const eventsEngine = injector({ const handlersController = getHandlersController(element, event.type); handlersController.callHandlers(event, extraParameters); })), -}); +} as EventsEngine); function applyForEach(args, method) { const element = args[0]; @@ -457,7 +481,7 @@ function normalizeEventArguments(callback) { } callback.call(this, src, config); - }; + } as EventFactory; Object.assign(eventsEngine.Event.prototype, { _propagationStopped: false, _immediatePropagationStopped: false, @@ -622,7 +646,7 @@ hookTouchProps(addProperty); const beforeSetStrategy = Callbacks(); const afterSetStrategy = Callbacks(); -eventsEngine.set = function (engine) { +eventsEngine.set = function (engine: Injection) { beforeSetStrategy.fire(); eventsEngine.inject(engine); initEvent(engine.Event); @@ -631,7 +655,7 @@ eventsEngine.set = function (engine) { eventsEngine.subscribeGlobal = function () { applyForEach(arguments, normalizeOnArguments(function () { - const args = arguments; + const args: any = arguments; eventsEngine.on.apply(this, args); diff --git a/packages/devextreme/js/__internal/grids/new/card_view/content_view/content/card/card.tsx b/packages/devextreme/js/__internal/grids/new/card_view/content_view/content/card/card.tsx index 0e5364fe2815..4baa5294c769 100644 --- a/packages/devextreme/js/__internal/grids/new/card_view/content_view/content/card/card.tsx +++ b/packages/devextreme/js/__internal/grids/new/card_view/content_view/content/card/card.tsx @@ -151,8 +151,8 @@ export class Card extends Component { const cardRole = Template ? 'presentation' : 'application'; - const coverId = new Guid(); - const contentId = new Guid(); + const coverId = new Guid().toString(); + const contentId = new Guid().toString(); return ( dateLocalization.format(value, format)) as string; + this._formatPattern = getFormat( + (value) => dateLocalization.format(value, format) as string, + ) as string; } return this._formatPattern; @@ -487,7 +488,7 @@ class DateBoxMask< .split(quantifierRegexp) .map((sourcePart) => (quantifierRegexp.test(sourcePart) ? sourcePart - : numberLocalization.convertDigits(sourcePart, false)) as string) + : numberLocalization.convertDigits(sourcePart, false))) .join(''); this._regExpInfo.regexp = new RegExp(convertedSource, flags); } diff --git a/packages/devextreme/js/__internal/ui/number_box/m_number_box.mask.ts b/packages/devextreme/js/__internal/ui/number_box/m_number_box.mask.ts index 61c30aff7988..551fd0c65649 100644 --- a/packages/devextreme/js/__internal/ui/number_box/m_number_box.mask.ts +++ b/packages/devextreme/js/__internal/ui/number_box/m_number_box.mask.ts @@ -518,7 +518,7 @@ class NumberBoxMask extends NumberBoxBase { parsedValue = Math.abs(this._parsedValue * 0); } - if (isNaN(parsedValue)) { + if (parsedValue === undefined || (typeof parsedValue === 'number' && isNaN(parsedValue))) { return undefined; } @@ -546,7 +546,7 @@ class NumberBoxMask extends NumberBoxBase { const sign = number.getSign(text, format?.formatter || format); const textWithoutStubs = this._removeStubs(text, true); const parsedValue = this._parse(textWithoutStubs, format); - const parsedValueSign = parsedValue < 0 ? -1 : 1; + const parsedValueSign = parsedValue != null && parsedValue < 0 ? -1 : 1; const parsedValueWithSign = isNumeric(parsedValue) && sign !== parsedValueSign ? sign * parsedValue : parsedValue; return parsedValueWithSign; diff --git a/packages/devextreme/js/__internal/ui/slider/m_slider.ts b/packages/devextreme/js/__internal/ui/slider/m_slider.ts index 819c39d69569..8f4ae61ae359 100644 --- a/packages/devextreme/js/__internal/ui/slider/m_slider.ts +++ b/packages/devextreme/js/__internal/ui/slider/m_slider.ts @@ -396,7 +396,7 @@ class Slider< .appendTo(this._$wrapper); } - this._$minLabel.text(numberLocalization.format(min, labelFormat)); + this._$minLabel.text(numberLocalization.format(min!, labelFormat)); if (!this._$maxLabel) { this._$maxLabel = $('
') @@ -404,7 +404,7 @@ class Slider< .appendTo(this._$wrapper); } - this._$maxLabel.text(numberLocalization.format(max, labelFormat)); + this._$maxLabel.text(numberLocalization.format(max!, labelFormat)); // eslint-disable-next-line @typescript-eslint/restrict-plus-operands, @typescript-eslint/no-base-to-string this.$element().addClass(SLIDER_LABEL_POSITION_CLASS_PREFIX + position); diff --git a/packages/devextreme/js/__internal/ui/validation_engine.ts b/packages/devextreme/js/__internal/ui/validation_engine.ts index 02c0b700f9ba..8624a1e47e5a 100644 --- a/packages/devextreme/js/__internal/ui/validation_engine.ts +++ b/packages/devextreme/js/__internal/ui/validation_engine.ts @@ -238,7 +238,9 @@ class NumericRuleValidator extends SyncRuleValidator { return true; } if (rule.useCultureSettings && isString(value)) { - return !isNaN(numberLocalization.parse(value)); + const parsedValue = numberLocalization.parse(value); + + return parsedValue === null || (parsedValue !== undefined && !isNaN(parsedValue)); } return isNumeric(value); }