Skip to content

Commit

Permalink
refactor(core)!: tuiFormatNumber(value, configs) new function signa…
Browse files Browse the repository at this point in the history
…ture (#2309)

* refactor(core)!: `tuiFormatNumber(value, configs)` new function signature

* refactor(core)!: `TuiNumberFormatSettings` add `decimalLimit`

* refactor(core)!: `FormatNumberPipe` replace all optional arguments with single object

* feat(core): new constant `TUI_DEFAULT_NUMBER_FORMAT`
  • Loading branch information
nsbarsukov authored Aug 9, 2022
1 parent e156c21 commit d5277c2
Show file tree
Hide file tree
Showing 19 changed files with 242 additions and 86 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,7 @@ export class TuiIntegerPartPipe implements PipeTransform {
transform(value: number, precision: number): string {
return tuiFormatNumber(
Math.floor(Math.abs(Number(value.toFixed(precision)))),
null,
this.numberFormat.decimalSeparator,
this.numberFormat.thousandSeparator,
this.numberFormat,
);
}
}
29 changes: 24 additions & 5 deletions projects/cdk/schematics/ng-update/steps/migrate-templates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import {
import {
findAttributeOnElementWithAttrs,
findAttributeOnElementWithTag,
findElementsInTemplateByFn,
findElementsByTagName,
findElementsInTemplateByFn,
findElementsWithAttribute,
hasElementAttribute,
} from '../../utils/templates/elements';
Expand Down Expand Up @@ -39,6 +39,7 @@ import {
import {replaceTag} from '../../utils/replace-tag';
import {migratePolymorpheus} from './migrate-polymorpheus';
import {addImportToClosestModule} from '../../utils/add-import-to-closest-module';
import {TODO_MARK} from '../../utils/insert-todo';

export function migrateTemplates(fileSystem: DevkitFileSystem): void {
infoLog(`${SMALL_TAB_SYMBOL}${REPLACE_SYMBOL} migrating templates...`);
Expand All @@ -56,6 +57,7 @@ export function migrateTemplates(fileSystem: DevkitFileSystem): void {
removeInputs,
migratePolymorpheus,
replaceInputValues,
addWarningForFormatNumberPipe,
];

componentWithTemplatesPaths.forEach(resource => {
Expand Down Expand Up @@ -177,10 +179,7 @@ function addHTMLCommentTags({
.map(el => (el.sourceCodeLocation?.startOffset || 0) + templateOffset);

elementStartOffsets.forEach(offset => {
recorder.insertRight(
offset,
`<!-- TODO: (Taiga UI migration) ${comment} -->\n`,
);
recorder.insertRight(offset, `<!-- ${TODO_MARK} ${comment} -->\n`);
});
});
}
Expand Down Expand Up @@ -351,6 +350,26 @@ function migrateTuiHideSelectedPipe({
});
}

function addWarningForFormatNumberPipe({
resource,
fileSystem,
recorder,
}: {
resource: TemplateResource;
recorder: UpdateRecorder;
fileSystem: DevkitFileSystem;
}): void {
const template = getTemplateFromTemplateResource(resource, fileSystem);
const templateOffset = getTemplateOffset(resource);

if (template.match(/\|\s*tuiFormatNumber\s*:\s/gi)) {
recorder.insertLeft(
templateOffset && templateOffset + 1,
`<!-- ${TODO_MARK} tuiFormatNumber pipe has new API. See https://taiga-ui.dev/pipes/format-number -->`,
);
}
}

function replaceInputValues({
resource,
recorder,
Expand Down
32 changes: 32 additions & 0 deletions projects/cdk/schematics/ng-update/steps/replace-functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export function replaceFunctions() {
replaceFallbackValue(getNamedImportReferences('fallbackValue', '@taiga-ui/cdk'));
replaceCustomEvent(getNamedImportReferences('tuiCustomEvent', '@taiga-ui/cdk'));
replaceClosestElement(getNamedImportReferences('getClosestElement', '@taiga-ui/cdk'));
modifyFormatNumberArgs();
replaceDeprecatedFunction();

successLog(`${SMALL_TAB_SYMBOL}${SUCCESS_SYMBOL} functions replaced \n`);
Expand Down Expand Up @@ -101,3 +102,34 @@ function replaceFallbackValue(references: Node[]) {
}
});
}

function modifyFormatNumberArgs(): void {
[
...getNamedImportReferences('formatNumber', '@taiga-ui/core'),
...getNamedImportReferences('tuiFormatNumber', '@taiga-ui/core'),
]
.map(ref => ref.getParent())
.filter(Node.isCallExpression)
.forEach(fn => {
const args = fn.getArguments();

if (args.length > 1) {
const [
value,
decimalLimit = `Infinity`,
decimalSeparator = `','`,
thousandSeparator = `'\u00A0'`,
zeroPadding = true,
] = args.map(arg => arg.getText());
const notNullDecimalLimit =
decimalLimit === `null` ? `Infinity` : decimalLimit;
const conditionalDecimalLimit = !Number.isNaN(+notNullDecimalLimit)
? notNullDecimalLimit
: `${decimalLimit} === null ? Infinity : ${decimalLimit}`;

fn.replaceWithText(
`tuiFormatNumber(${value}, {decimalLimit: ${conditionalDecimalLimit}, decimalSeparator: ${decimalSeparator}, thousandSeparator: ${thousandSeparator}, zeroPadding: ${zeroPadding}})`,
);
}
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,32 @@ import {createAngularJson} from '../../utils/create-angular-json';
const collectionPath = join(__dirname, '../../migration.json');

const AFTER = `import {Component} from '@angular/core';
import {
TUI_NUMBER_FORMAT,
tuiFormatNumber,
TuiNumberFormatSettings,
} from '@taiga-ui/core';
tuiFormatNumber(1000);
tuiFormatNumber(1.234, {decimalLimit: 2, decimalSeparator: ',', thousandSeparator: ' ', zeroPadding: true});
tuiFormatNumber(123.45, {decimalLimit: 3, decimalSeparator: '.', thousandSeparator: ' ', zeroPadding: true});
tuiFormatNumber(12345.67, {decimalLimit: 4, decimalSeparator: ',', thousandSeparator: '.', zeroPadding: true});
tuiFormatNumber(27, {decimalLimit: 5, decimalSeparator: ',', thousandSeparator: '.', zeroPadding: false});
const dynamicDecimalLimit = Math.random() > 0.5;
const decimalSeparatorVariable = ',';
const thousandSeparatorVariable = '_';
const zeroPaddingVariable = false;
tuiFormatNumber(42, {decimalLimit: dynamicDecimalLimit === null ? Infinity : dynamicDecimalLimit, decimalSeparator: decimalSeparatorVariable, thousandSeparator: thousandSeparatorVariable, zeroPadding: zeroPaddingVariable});
@Component({templateUrl: './app.template.html'})
export class AppComponent extends AbstractTuiController {
some = number ?? 5;
get formattedNumber(): number {
return tuiFormatNumber(Math.floor(rawNumber), {decimalLimit: Infinity, decimalSeparator: this.numberFormat.decimalSeparator, thousandSeparator: this.numberFormat.thousandSeparator, zeroPadding: true});
}
method(): void {
return someFn(b ?? "some");
}
Expand All @@ -27,6 +48,8 @@ export class AppComponent extends AbstractTuiController {
this.some = '1000'.padStart(10, " ");
return String(this.day).padStart(2, '0');
}
constructor(@Inject(TUI_NUMBER_FORMAT) private readonly numberFormat: TuiNumberFormatSettings) {}
}
expect(element.closest('div')).toEqual(div);
Expand All @@ -40,11 +63,37 @@ const event = new CustomEvent("hello", {

const BEFORE = `import {Component} from '@angular/core';
import { fallbackValue, tuiCustomEvent, getClosestElement, padStart } from '@taiga-ui/cdk';
import {
TUI_NUMBER_FORMAT,
tuiFormatNumber,
TuiNumberFormatSettings,
} from '@taiga-ui/core';
tuiFormatNumber(1000);
tuiFormatNumber(1.234, 2);
tuiFormatNumber(123.45, 3, '.');
tuiFormatNumber(12345.67, 4, ',', '.');
tuiFormatNumber(27, 5, ',', '.', false);
const dynamicDecimalLimit = Math.random() > 0.5;
const decimalSeparatorVariable = ',';
const thousandSeparatorVariable = '_';
const zeroPaddingVariable = false;
tuiFormatNumber(42, dynamicDecimalLimit, decimalSeparatorVariable, thousandSeparatorVariable, zeroPaddingVariable);
@Component({templateUrl: './app.template.html'})
export class AppComponent extends AbstractTuiController {
some = fallbackValue(number, 5);
get formattedNumber(): number {
return tuiFormatNumber(
Math.floor(rawNumber),
null,
this.numberFormat.decimalSeparator,
this.numberFormat.thousandSeparator,
);
}
method(): void {
return someFn(fallbackValue<string>(b, "some"));
}
Expand All @@ -53,6 +102,8 @@ export class AppComponent extends AbstractTuiController {
this.some = padStart('1000', 10);
return padStart(String(this.day), 2, '0');
}
constructor(@Inject(TUI_NUMBER_FORMAT) private readonly numberFormat: TuiNumberFormatSettings) {}
}
expect(getClosestElement(element, 'div')).toEqual(div);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ const TEMPLATE_BEFORE = `
<tui-field-error formControlName="control"></tui-field-error>
<tui-field-error formControlName="control" [order]="order"></tui-field-error>
<p>Formatted number: {{ 10500.33 | tuiFormatNumber: 4:'.':'_':false }}</p>
<table>
<thead>
<tr tuiThGroup>
Expand Down Expand Up @@ -171,7 +173,7 @@ const TEMPLATE_BEFORE = `
</tui-breadcrumbs>
`;

const TEMPLATE_AFTER = `
const TEMPLATE_AFTER = `<!-- TODO: (Taiga UI migration) tuiFormatNumber pipe has new API. See https://taiga-ui.dev/pipes/format-number -->
<label
${''}
tuiLabel="Step"
Expand All @@ -180,6 +182,8 @@ const TEMPLATE_AFTER = `
<tui-error [error]="[] | tuiFieldError | async" formControlName="control"></tui-error>
<tui-error [error]="order | tuiFieldError | async" formControlName="control"></tui-error>
<p>Formatted number: {{ 10500.33 | tuiFormatNumber: 4:'.':'_':false }}</p>
<table>
<thead>
<tr tuiThGroup>
Expand Down Expand Up @@ -323,14 +327,14 @@ const TEMPLATE_AFTER = `
`;

const COMPONENT_BEFORE = `
@Component({template: '<tui-group><div></div></tui-group>'})
@Component({template: '<tui-group><div [data-value]="27.3333 | tuiFormatNumber: 2"></div></tui-group>'})
export class TestComponentInline {
aware = TUI_MOBILE_AWARE;
}
`;

const COMPONENT_AFTER = `
@Component({template: '<div tuiGroup><div></div></div>'})
@Component({template: '<!-- TODO: (Taiga UI migration) tuiFormatNumber pipe has new API. See https://taiga-ui.dev/pipes/format-number --><div tuiGroup><div [data-value]="27.3333 | tuiFormatNumber: 2"></div></div>'})
export class TestComponentInline {
aware = TUI_MOBILE_AWARE;
}
Expand Down
4 changes: 3 additions & 1 deletion projects/cdk/schematics/utils/insert-todo.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import {Identifier} from 'ng-morph';

export const TODO_MARK = `TODO: (Taiga UI migration)`;

export function insertTodo(identifier: Identifier, message: string) {
const startLinePos = identifier.getStartLinePos();
const sourceFile = identifier.getSourceFile();
sourceFile.insertText(startLinePos, `// TODO: (Taiga UI migration) ${message}\n`);
sourceFile.insertText(startLinePos, `// ${TODO_MARK} ${message}\n`);
}
9 changes: 9 additions & 0 deletions projects/core/constants/default-number-format.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import {CHAR_NO_BREAK_SPACE} from '@taiga-ui/cdk';
import {TuiNumberFormatSettings} from '@taiga-ui/core/interfaces';

export const TUI_DEFAULT_NUMBER_FORMAT: TuiNumberFormatSettings = {
decimalLimit: Infinity,
decimalSeparator: `,`,
thousandSeparator: CHAR_NO_BREAK_SPACE,
zeroPadding: true,
};
1 change: 1 addition & 0 deletions projects/core/constants/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export * from './absolute-box-sizes';
export * from './decimal-symbols';
export * from './default-icons-path';
export * from './default-marker-handler';
export * from './default-number-format';
export * from './described-by';
export * from './editing-keys';
export * from './events';
Expand Down
18 changes: 16 additions & 2 deletions projects/core/interfaces/number-format-settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,25 @@ import {TuiDecimalSymbol} from '@taiga-ui/core/types';

/**
* Formatting configuration for displayed numbers
* decimalSeparator - example: 100,45 (',' by default)
* thousandSeparator - example: 360 000 (' ' by default)
*/
export interface TuiNumberFormatSettings {
/**
* Number of digits of decimal part.
* @note Use `Infinity` to keep untouched.
*/
readonly decimalLimit: number;
/**
* Separator between the integer and the decimal part.
* @example 0,42 (',' by default)
*/
readonly decimalSeparator: TuiDecimalSymbol;
/**
* Separator between thousands.
* @example 360 000 (' ' by default)
*/
readonly thousandSeparator: string;
/**
* Enable zeros at the end of decimal part.
*/
readonly zeroPadding: boolean;
}
21 changes: 3 additions & 18 deletions projects/core/pipes/format-number/format-number.pipe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,9 @@ export class TuiFormatNumberPipe implements PipeTransform {
* Formats number adding thousand separators and correct decimal separator
* padding decimal part with zeroes to given length
* @param value number
* @param decimalSeparator
* @param thousandSeparator
* @param decimalLimit number of digits of decimal part, null to keep untouched
* @param zeroPadding enable zeros at the end of decimal part
* @param settings See {@link TuiNumberFormatSettings}
*/
transform(
value: number,
decimalLimit: number | null = null,
decimalSeparator: string = this.numberFormat.decimalSeparator,
thousandSeparator: string = this.numberFormat.thousandSeparator,
zeroPadding: boolean = this.numberFormat.zeroPadding,
): string {
return tuiFormatNumber(
value,
decimalLimit,
decimalSeparator,
thousandSeparator,
zeroPadding,
);
transform(value: number, settings: Partial<TuiNumberFormatSettings> = {}): string {
return tuiFormatNumber(value, {...this.numberFormat, ...settings});
}
}
8 changes: 2 additions & 6 deletions projects/core/tokens/number-format.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
import {InjectionToken} from '@angular/core';
import {CHAR_NO_BREAK_SPACE} from '@taiga-ui/cdk';
import {TUI_DEFAULT_NUMBER_FORMAT} from '@taiga-ui/core/constants';
import {TuiNumberFormatSettings} from '@taiga-ui/core/interfaces';

export const TUI_NUMBER_FORMAT = new InjectionToken<TuiNumberFormatSettings>(
`Formatting configuration for displayed numbers`,
{
factory: () => ({
decimalSeparator: `,`,
thousandSeparator: CHAR_NO_BREAK_SPACE,
zeroPadding: true,
}),
factory: () => TUI_DEFAULT_NUMBER_FORMAT,
},
);
21 changes: 10 additions & 11 deletions projects/core/utils/format/format-number.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,30 @@
import {CHAR_HYPHEN, CHAR_NO_BREAK_SPACE} from '@taiga-ui/cdk';
import {CHAR_HYPHEN} from '@taiga-ui/cdk';
import {TUI_DEFAULT_NUMBER_FORMAT} from '@taiga-ui/core/constants';
import {TuiNumberFormatSettings} from '@taiga-ui/core/interfaces';

import {tuiGetFractionPartPadded} from './get-fractional-part-padded';

// TODO: refactor later to `formatNumber(value: number, options: Partial<AllTheStuff>)`
/**
* Formats number adding a thousand separators and correct decimal separator
* padding decimal part with zeroes to given length
*
* @param value the input number
* @param decimalLimit number of digits of decimal part, null to keep untouched
* @param decimalSeparator separator between the integer and the decimal part
* @param thousandSeparator separator between thousands
* @param zeroPadding enable zeros at the end of decimal part
* @param settings See {@link TuiNumberFormatSettings}
* @return the formatted string
*/
export function tuiFormatNumber(
value: number,
decimalLimit: number | null = null,
decimalSeparator: string = `,`,
thousandSeparator: string = CHAR_NO_BREAK_SPACE,
zeroPadding: boolean = true,
settings: Partial<TuiNumberFormatSettings> = {},
): string {
const {decimalLimit, decimalSeparator, thousandSeparator, zeroPadding} = {
...TUI_DEFAULT_NUMBER_FORMAT,
...settings,
};
const integerPartString = String(Math.floor(Math.abs(value)));

let fractionPartPadded = tuiGetFractionPartPadded(value, decimalLimit);

if (decimalLimit !== null) {
if (Number.isFinite(decimalLimit)) {
if (zeroPadding) {
const zeroPaddingSize: number = Math.max(
decimalLimit - fractionPartPadded.length,
Expand Down
Loading

0 comments on commit d5277c2

Please sign in to comment.