Browse Source

Add support for international formatted numbers

pull/2843/head
Thomas Kaul 2 years ago
parent
commit
3efa322f90
  1. 6
      apps/api/src/app/info/info.service.ts
  2. 14
      apps/api/src/services/data-provider/manual/manual.service.ts
  3. 32
      libs/common/src/lib/helper.spec.ts
  4. 19
      libs/common/src/lib/helper.ts
  5. 1
      package.json
  6. 14
      yarn.lock

6
apps/api/src/app/info/info.service.ts

@ -195,11 +195,11 @@ export class InfoService {
const $ = cheerio.load(body);
return extractNumberFromString(
$(
return extractNumberFromString({
value: $(
`a[href="/ghostfolio/ghostfolio/graphs/contributors"] .Counter`
).text()
);
});
} catch (error) {
Logger.error(error, 'InfoService - GitHub');

14
apps/api/src/services/data-provider/manual/manual.service.ts

@ -248,13 +248,19 @@ export class ManualService implements DataProviderInterface {
jsonpath.query(data, scraperConfiguration.selector)[0]
);
return extractNumberFromString(value);
return extractNumberFromString({ value });
} else {
const $ = cheerio.load(body);
let locale: string;
return extractNumberFromString(
$(scraperConfiguration.selector).first().text()
);
try {
locale = $('html').attr('lang');
} catch {}
return extractNumberFromString({
locale,
value: $(scraperConfiguration.selector).first().text()
});
}
} catch (error) {
throw error;

32
libs/common/src/lib/helper.spec.ts

@ -3,11 +3,37 @@ import { extractNumberFromString } from '@ghostfolio/common/helper';
describe('Helper', () => {
describe('Extract number from string', () => {
it('Get decimal number', async () => {
expect(extractNumberFromString('999.99')).toEqual(999.99);
expect(extractNumberFromString({ value: '999.99' })).toEqual(999.99);
});
it('Get decimal number with group', async () => {
expect(extractNumberFromString('99.999,99')).toEqual(99999.99);
it('Get decimal number (with spaces)', async () => {
expect(extractNumberFromString({ value: ' 999.99 ' })).toEqual(999.99);
});
it('Get decimal number (with currency)', async () => {
expect(extractNumberFromString({ value: '999.99 CHF' })).toEqual(999.99);
});
it('Get decimal number (comma notation)', async () => {
expect(
extractNumberFromString({ locale: 'de-DE', value: '999,99' })
).toEqual(999.99);
});
it('Get decimal number with group (dot notation)', async () => {
expect(
extractNumberFromString({ locale: 'de-CH', value: '99’999.99' })
).toEqual(99999.99);
});
it('Get decimal number with group (comma notation)', async () => {
expect(
extractNumberFromString({ locale: 'de-DE', value: '99.999,99' })
).toEqual(99999.99);
});
it('Not a number', async () => {
expect(extractNumberFromString({ value: 'X' })).toEqual(NaN);
});
});
});

19
libs/common/src/lib/helper.ts

@ -1,4 +1,5 @@
import * as currencies from '@dinero.js/currencies';
import { NumberParser } from '@internationalized/number';
import { DataSource, MarketData } from '@prisma/client';
import Big from 'big.js';
import {
@ -20,8 +21,6 @@ export const DATE_FORMAT = 'yyyy-MM-dd';
export const DATE_FORMAT_MONTHLY = 'MMMM yyyy';
export const DATE_FORMAT_YEARLY = 'yyyy';
const NUMERIC_REGEXP = /[-]{0,1}[\d]*[.,]{0,1}[\d]+/g;
export function calculateBenchmarkTrend({
days,
historicalData
@ -120,10 +119,20 @@ export function encodeDataSource(aDataSource: DataSource) {
return undefined;
}
export function extractNumberFromString(aString: string): number {
export function extractNumberFromString({
locale = 'en-US',
value
}: {
locale?: string;
value: string;
}): number {
try {
const [numberString] = aString.match(NUMERIC_REGEXP);
return parseFloat(numberString.trim());
// Remove non-numeric characters (excluding international formatting characters)
const numericValue = value.replace(/[^\d.,'’\s]/g, '');
let parser = new NumberParser(locale);
return parser.parse(numericValue);
} catch {
return undefined;
}

1
package.json

@ -73,6 +73,7 @@
"@dfinity/identity": "0.15.7",
"@dfinity/principal": "0.15.7",
"@dinero.js/currencies": "2.0.0-alpha.8",
"@internationalized/number": "3.5.0",
"@nestjs/bull": "10.0.1",
"@nestjs/cache-manager": "2.1.0",
"@nestjs/common": "10.1.3",

14
yarn.lock

@ -3063,6 +3063,13 @@
resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz#e5211452df060fa8522b55c7b3c0c4d1981cb044"
integrity sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==
"@internationalized/number@3.5.0":
version "3.5.0"
resolved "https://registry.yarnpkg.com/@internationalized/number/-/number-3.5.0.tgz#9de6018424b441a6545f209afa286ad7df4a2906"
integrity sha512-ZY1BW8HT9WKYvaubbuqXbbDdHhOUMfE2zHHFJeTppid0S+pc8HtdIxFxaYMsGjCb4UsF+MEJ4n2TfU7iHnUK8w==
dependencies:
"@swc/helpers" "^0.5.0"
"@ioredis/commands@^1.1.1":
version "1.2.0"
resolved "https://registry.yarnpkg.com/@ioredis/commands/-/commands-1.2.0.tgz#6d61b3097470af1fdbbe622795b8921d42018e11"
@ -6201,6 +6208,13 @@
resolved "https://registry.yarnpkg.com/@swc/counter/-/counter-0.1.2.tgz#bf06d0770e47c6f1102270b744e17b934586985e"
integrity sha512-9F4ys4C74eSTEUNndnER3VJ15oru2NumfQxS8geE+f3eB5xvfxpWyqE5XlVnxb/R14uoXi6SLbBwwiDSkv+XEw==
"@swc/helpers@^0.5.0":
version "0.5.3"
resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.5.3.tgz#98c6da1e196f5f08f977658b80d6bd941b5f294f"
integrity sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==
dependencies:
tslib "^2.4.0"
"@swc/types@^0.1.5":
version "0.1.5"
resolved "https://registry.yarnpkg.com/@swc/types/-/types-0.1.5.tgz#043b731d4f56a79b4897a3de1af35e75d56bc63a"

Loading…
Cancel
Save