Skip to content

Commit

Permalink
Convert number-format to TypeScript (#75)
Browse files Browse the repository at this point in the history
* Convert number-format to TypeScript

* return string

* unit test 100%

* Allow developer to specify return type for loader

* add doc
  • Loading branch information
kristw authored and zhaoyongjie committed Nov 17, 2021
1 parent 3fd9636 commit d6f25a7
Show file tree
Hide file tree
Showing 21 changed files with 217 additions and 158 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
"build": "yarn run build:cjs && yarn run build:esm && yarn run type:dts",
"build:cjs": "NODE_ENV=production beemo babel --extensions=\".js,.jsx,.ts,.tsx\" ./src --out-dir lib/ --minify --workspaces=\"@superset-ui/!(demo|generator-superset)\"",
"build:esm": "NODE_ENV=production beemo babel --extensions=\".js,.jsx,.ts,.tsx\" ./src --out-dir esm/ --esm --minify --workspaces=\"@superset-ui/!(demo|generator-superset)\"",
"type": "NODE_ENV=production beemo typescript --workspaces=\"@superset-ui/(connection|core|color|chart)\" --noEmit",
"type:dts": "NODE_ENV=production beemo typescript --workspaces=\"@superset-ui/(connection|core|color|chart)\" --emitDeclarationOnly",
"type": "NODE_ENV=production beemo typescript --workspaces=\"@superset-ui/(connection|core|color|chart|number-format)\" --noEmit",
"type:dts": "NODE_ENV=production beemo typescript --workspaces=\"@superset-ui/(connection|core|color|chart|number-format)\" --emitDeclarationOnly",
"lint": "beemo create-config prettier && beemo eslint \"./packages/*/{src,test,storybook}/**/*.{js,jsx,ts,tsx}\"",
"lint:fix": "beemo create-config prettier && beemo eslint --fix \"./packages/*/{src,test,storybook}/**/*.{js,jsx,ts,tsx}\"",
"jest": "beemo jest --color --coverage --react",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,30 @@ interface ItemWithValue<T> {
}

interface ItemWithLoader<T> {
loader: () => T | Promise<T>;
loader: () => T;
}

export interface RegistryConfig {
name?: string;
overwritePolicy?: OverwritePolicy;
}

export default class Registry<V> {
/**
* Registry class
*
* Can use generic to specify type of item in the registry
* @type V Type of value
* @type W Type of value returned from loader function when using registerLoader().
* W can be either V, Promise<V> or V | Promise<V>
* Set W=V when does not support asynchronous loader.
* By default W is set to V | Promise<V> to support
* both synchronous and asynchronous loaders.
*/
export default class Registry<V, W extends V | Promise<V> = V | Promise<V>> {
name: string;
overwritePolicy: OverwritePolicy;
items: {
[key: string]: ItemWithValue<V> | ItemWithLoader<V>;
[key: string]: ItemWithValue<V> | ItemWithLoader<W>;
};

promises: {
Expand Down Expand Up @@ -70,7 +81,7 @@ export default class Registry<V> {
return this;
}

registerLoader(key: string, loader: () => V | Promise<V>) {
registerLoader(key: string, loader: () => W) {
const item = this.items[key];
const willOverwrite =
this.has(key) && (('loader' in item && item.loader !== loader) || 'value' in item);
Expand All @@ -89,7 +100,7 @@ export default class Registry<V> {
return this;
}

get(key: string): V | Promise<V> | undefined {
get(key: string): V | W | undefined {
const item = this.items[key];
if (item !== undefined) {
if ('loader' in item) {
Expand All @@ -109,7 +120,7 @@ export default class Registry<V> {
}
const item = this.get(key);
if (item !== undefined) {
const newPromise = Promise.resolve(item);
const newPromise = Promise.resolve(item) as Promise<V>;
this.promises[key] = newPromise;

return newPromise;
Expand All @@ -120,7 +131,7 @@ export default class Registry<V> {

getMap() {
return this.keys().reduce<{
[key: string]: V | Promise<V> | undefined;
[key: string]: V | W | undefined;
}>((prev, key) => {
const map = prev;
map[key] = this.get(key);
Expand Down Expand Up @@ -148,22 +159,22 @@ export default class Registry<V> {
return Object.keys(this.items);
}

values(): Array<V | Promise<V> | undefined> {
values(): (V | W | undefined)[] {
return this.keys().map(key => this.get(key));
}

valuesAsPromise(): Promise<V[]> {
return Promise.all(this.keys().map(key => this.getAsPromise(key)));
}

entries(): Array<{ key: string; value: V | Promise<V> | undefined }> {
entries(): { key: string; value: V | W | undefined }[] {
return this.keys().map(key => ({
key,
value: this.get(key),
}));
}

entriesAsPromise(): Promise<Array<{ key: string; value: V }>> {
entriesAsPromise(): Promise<{ key: string; value: V }[]> {
const keys = this.keys();

return Promise.all(keys.map(key => this.getAsPromise(key))).then(values =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ export interface RegistryWithDefaultKeyConfig extends RegistryConfig {
setFirstItemAsDefault?: boolean;
}

export default class RegistryWithDefaultKey<V> extends Registry<V> {
export default class RegistryWithDefaultKey<
V,
W extends V | Promise<V> = V | Promise<V>
> extends Registry<V, W> {
initialDefaultKey?: string;
defaultKey?: string;
setFirstItemAsDefault: boolean;
Expand Down Expand Up @@ -41,7 +44,7 @@ export default class RegistryWithDefaultKey<V> extends Registry<V> {
return this;
}

registerLoader(key: string, loader: () => V | Promise<V>) {
registerLoader(key: string, loader: () => W) {
super.registerLoader(key, loader);
// If there is no default, set as default
if (this.setFirstItemAsDefault && !this.defaultKey) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
},
"dependencies": {
"@superset-ui/core": "^0.8.0",
"@types/d3-format": "^1.3.0",
"d3-format": "^1.3.2"
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { ExtensibleFunction, isRequired } from '@superset-ui/core';
import { NumberFormatFunction } from './types';

export const PREVIEW_VALUE = 12345.432;

export interface NumberFormatterConfig {
id: string;
label?: string;
description?: string;
formatFunc: NumberFormatFunction;
isInvalid?: boolean;
}

export default class NumberFormatter extends ExtensibleFunction {
id: string;
label: string;
description: string;
formatFunc: NumberFormatFunction;
isInvalid: boolean;

constructor(config: NumberFormatterConfig) {
super((value: number) => this.format(value));

const {
id = isRequired('config.id'),
label,
description = '',
formatFunc = isRequired('config.formatFunc'),
isInvalid = false,
} = config;
this.id = id;
this.label = label || id;
this.description = description;
this.formatFunc = formatFunc;
this.isInvalid = isInvalid;
}

format(value: number | null | undefined) {
if (value === null || value === undefined || Number.isNaN(value)) {
return `${value}`;
} else if (value === Number.POSITIVE_INFINITY) {
return '∞';
} else if (value === Number.NEGATIVE_INFINITY) {
return '-∞';
}

return this.formatFunc(value);
}

preview(value: number = PREVIEW_VALUE) {
return `${value} => ${this.format(value)}`;
}
}
Original file line number Diff line number Diff line change
@@ -1,20 +1,24 @@
import { RegistryWithDefaultKey } from '@superset-ui/core';
import createD3NumberFormatter from './factories/createD3NumberFormatter';
import NumberFormats from './NumberFormats';
import NumberFormatter from './NumberFormatter';

export default class NumberFormatterRegistry extends RegistryWithDefaultKey {
export default class NumberFormatterRegistry extends RegistryWithDefaultKey<
NumberFormatter,
NumberFormatter
> {
constructor() {
super({
initialDefaultKey: NumberFormats.SI,
name: 'NumberFormatter',
});
}

get(formatterId) {
const targetFormat = (formatterId || this.defaultKey).trim();
get(formatterId?: string) {
const targetFormat = `${formatterId || this.defaultKey}`.trim();

if (this.has(targetFormat)) {
return super.get(targetFormat);
return super.get(targetFormat) as NumberFormatter;
}

// Create new formatter if does not exist
Expand All @@ -26,7 +30,7 @@ export default class NumberFormatterRegistry extends RegistryWithDefaultKey {
return formatter;
}

format(formatterId, value) {
format(formatterId: string, value: number | null | undefined): string {
return this.get(formatterId)(value);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ const getInstance = makeSingleton(NumberFormatterRegistry);

export default getInstance;

export function getNumberFormatter(format) {
export function getNumberFormatter(format: string) {
return getInstance().get(format);
}

export function formatNumber(format, value) {
export function formatNumber(format: string, value: number | null | undefined) {
return getInstance().format(format, value);
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import { format as d3Format } from 'd3-format';
import { isRequired } from '@superset-ui/core';
import NumberFormatter from '../NumberFormatter';
import { NumberFormatFunction } from '../types';

export default function createD3NumberFormatter({
description,
formatString = isRequired('formatString'),
label,
} = {}) {
let formatFunc;
export default function createD3NumberFormatter(config: {
description?: string;
formatString: string;
label?: string;
}) {
const { description, formatString = isRequired('config.formatString'), label } = config;

let formatFunc: NumberFormatFunction;
let isInvalid = false;

try {
Expand All @@ -17,12 +20,10 @@ export default function createD3NumberFormatter({
isInvalid = true;
}

const id = formatString;

return new NumberFormatter({
description,
formatFunc,
id,
id: formatString,
isInvalid,
label,
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
import { format as d3Format } from 'd3-format';
import NumberFormatter from '../NumberFormatter';

export default function createSiAtMostNDigitFormatter({ description, n = 3, id, label } = {}) {
export default function createSiAtMostNDigitFormatter(
config: {
description?: string;
n?: number;
id?: string;
label?: string;
} = {},
) {
const { description, n = 3, id, label } = config;
const siFormatter = d3Format(`.${n}s`);

return new NumberFormatter({
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/* eslint-disable-next-line import/prefer-default-export */
export type NumberFormatFunction = (value: number) => string;
Loading

0 comments on commit d6f25a7

Please sign in to comment.