From b15098f1f22c4320a58f1cc17106e0321c9217a3 Mon Sep 17 00:00:00 2001 From: bre1470 <40056287+bre1470@users.noreply.github.com> Date: Thu, 1 Aug 2024 17:10:40 +0200 Subject: [PATCH 01/10] Fixed distribution. --- package-build.json | 5 +- package-lock.json | 269 ++++++++++-------- package.json | 20 +- src/RNANews/RNANewsConnector.ts | 112 ++++---- src/RNANews/RNANewsConverter.ts | 13 +- src/RNANews/RNANewsJSON.ts | 21 +- src/RNANews/RNANewsOptions.ts | 14 + src/RNANews/index.ts | 9 +- .../CumulativeReturnSeriesConverter.ts | 3 +- .../Converters/DividendSeriesConverter.ts | 3 +- .../Converters/GrowthSeriesConverter.ts | 3 +- .../Converters/RatingSeriesConverter.ts | 3 +- src/TimeSeries/TimeSeriesConnector.ts | 7 +- src/TimeSeries/index.ts | 2 +- src/index.ts | 8 +- src/webpack.d.ts | 5 + tsconfig.json | 2 +- webpack.config.ts | 4 +- 18 files changed, 299 insertions(+), 204 deletions(-) create mode 100644 src/webpack.d.ts diff --git a/package-build.json b/package-build.json index ff29620..78f496e 100644 --- a/package-build.json +++ b/package-build.json @@ -1,6 +1,6 @@ { "private": true, - "version": "1.0.0", + "version": "0.1.0", "name": "@highcharts/morningstar-connectors", "license": "UNLICENSED", "description": "Highcharts Dashboards connectors for Morningstar Direct Web Services", @@ -12,8 +12,7 @@ "files": [ "es-modules/", "LICENSE.md", - "morningstar-*.js", - "morningstar-*.js.map", + "morningstar-*", "README.md" ], "keywords": [ diff --git a/package-lock.json b/package-lock.json index eb11925..822e318 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,7 +21,8 @@ "webpack-cli": "^5.1.4" }, "peerDependencies": { - "@highcharts/dashboards": "^2.2.0" + "@highcharts/dashboards": "^2.2.0", + "highcharts": ">=11.4.0" } }, "node_modules/@cspotcode/source-map-support": { @@ -420,27 +421,27 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "20.14.12", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.12.tgz", - "integrity": "sha512-r7wNXakLeSsGT0H1AU863vS2wa5wBOK4bWMjZz2wj+8nBx+m5PeIn0k8AloSLpRuiwdRQZwarZqHE4FNArPuJQ==", + "version": "22.0.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.0.2.tgz", + "integrity": "sha512-yPL6DyFwY5PiMVEwymNeqUTKsDczQBJ/5T7W/46RwLU/VH+AA8aT5TZkvBviLKLbbm0hlfftEkGrNzfRk/fofQ==", "dev": true, "license": "MIT", "dependencies": { - "undici-types": "~5.26.4" + "undici-types": "~6.11.1" } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.17.0.tgz", - "integrity": "sha512-pyiDhEuLM3PuANxH7uNYan1AaFs5XE0zw1hq69JBvGvE7gSuEoQl1ydtEe/XQeoC3GQxLXyOVa5kNOATgM638A==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.18.0.tgz", + "integrity": "sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "7.17.0", - "@typescript-eslint/type-utils": "7.17.0", - "@typescript-eslint/utils": "7.17.0", - "@typescript-eslint/visitor-keys": "7.17.0", + "@typescript-eslint/scope-manager": "7.18.0", + "@typescript-eslint/type-utils": "7.18.0", + "@typescript-eslint/utils": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -464,17 +465,17 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.17.0.tgz", - "integrity": "sha512-puiYfGeg5Ydop8eusb/Hy1k7QmOU6X3nvsqCgzrB2K4qMavK//21+PzNE8qeECgNOIoertJPUC1SpegHDI515A==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.18.0.tgz", + "integrity": "sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg==", "dev": true, "license": "BSD-2-Clause", "peer": true, "dependencies": { - "@typescript-eslint/scope-manager": "7.17.0", - "@typescript-eslint/types": "7.17.0", - "@typescript-eslint/typescript-estree": "7.17.0", - "@typescript-eslint/visitor-keys": "7.17.0", + "@typescript-eslint/scope-manager": "7.18.0", + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/typescript-estree": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0", "debug": "^4.3.4" }, "engines": { @@ -494,14 +495,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.17.0.tgz", - "integrity": "sha512-0P2jTTqyxWp9HiKLu/Vemr2Rg1Xb5B7uHItdVZ6iAenXmPo4SZ86yOPCJwMqpCyaMiEHTNqizHfsbmCFT1x9SA==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.18.0.tgz", + "integrity": "sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "7.17.0", - "@typescript-eslint/visitor-keys": "7.17.0" + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -512,14 +513,14 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.17.0.tgz", - "integrity": "sha512-XD3aaBt+orgkM/7Cei0XNEm1vwUxQ958AOLALzPlbPqb8C1G8PZK85tND7Jpe69Wualri81PLU+Zc48GVKIMMA==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.18.0.tgz", + "integrity": "sha512-XL0FJXuCLaDuX2sYqZUUSOJ2sG5/i1AAze+axqmLnSkNEVMVYLF+cbwlB2w8D1tinFuSikHmFta+P+HOofrLeA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "7.17.0", - "@typescript-eslint/utils": "7.17.0", + "@typescript-eslint/typescript-estree": "7.18.0", + "@typescript-eslint/utils": "7.18.0", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, @@ -540,9 +541,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.17.0.tgz", - "integrity": "sha512-a29Ir0EbyKTKHnZWbNsrc/gqfIBqYPwj3F2M+jWE/9bqfEHg0AMtXzkbUkOG6QgEScxh2+Pz9OXe11jHDnHR7A==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", + "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", "dev": true, "license": "MIT", "engines": { @@ -554,14 +555,14 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.17.0.tgz", - "integrity": "sha512-72I3TGq93t2GoSBWI093wmKo0n6/b7O4j9o8U+f65TVD0FS6bI2180X5eGEr8MA8PhKMvYe9myZJquUT2JkCZw==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.18.0.tgz", + "integrity": "sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/types": "7.17.0", - "@typescript-eslint/visitor-keys": "7.17.0", + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -583,16 +584,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.17.0.tgz", - "integrity": "sha512-r+JFlm5NdB+JXc7aWWZ3fKSm1gn0pkswEwIYsrGPdsT2GjsRATAKXiNtp3vgAAO1xZhX8alIOEQnNMl3kbTgJw==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.18.0.tgz", + "integrity": "sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "7.17.0", - "@typescript-eslint/types": "7.17.0", - "@typescript-eslint/typescript-estree": "7.17.0" + "@typescript-eslint/scope-manager": "7.18.0", + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/typescript-estree": "7.18.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -606,13 +607,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.17.0.tgz", - "integrity": "sha512-RVGC9UhPOCsfCdI9pU++K4nD7to+jTcMIbXTSOcrLqUEW6gF2pU1UUbYJKc9cvcRSK1UDeMJ7pdMxf4bhMpV/A==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.18.0.tgz", + "integrity": "sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "7.17.0", + "@typescript-eslint/types": "7.18.0", "eslint-visitor-keys": "^3.4.3" }, "engines": { @@ -926,13 +927,16 @@ } }, "node_modules/ansi-escapes": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.2.1.tgz", - "integrity": "sha512-4nJ3yixlEthEJ9Rk4vPcdBRkZvQZlYyu8j4/Mqz5sgIkddmEnH2Yj2ZrnP9S3tQOvSNRUIgVNF/1yPpRAGNRig==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.0.0.tgz", + "integrity": "sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw==", "dev": true, "license": "MIT", + "dependencies": { + "environment": "^1.0.0" + }, "engines": { - "node": ">=14.16" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -1079,9 +1083,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001643", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001643.tgz", - "integrity": "sha512-ERgWGNleEilSrHM6iUz/zJNSQTP8Mr21wDWpdgvRwcTXGAq6jMtOUPP4dqFPTdKqZ2wKTdtB+uucZ3MRpAUSmg==", + "version": "1.0.30001646", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001646.tgz", + "integrity": "sha512-dRg00gudiBDDTmUhClSdv3hqRfpbOnU28IpI1T6PBTLWa+kOj0681C8uML3PifYfREuBrVjDGhL3adYpBT6spw==", "dev": true, "funding": [ { @@ -1127,16 +1131,16 @@ } }, "node_modules/cli-cursor": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz", - "integrity": "sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", "dev": true, "license": "MIT", "dependencies": { - "restore-cursor": "^4.0.0" + "restore-cursor": "^5.0.0" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -1251,9 +1255,9 @@ } }, "node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", "dev": true, "license": "MIT", "dependencies": { @@ -1312,9 +1316,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.2.tgz", - "integrity": "sha512-kc4r3U3V3WLaaZqThjYz/Y6z8tJe+7K0bbjUVo3i+LWIypVdMx5nXCkwRe6SWbY6ILqLdc1rKcKmr3HoH7wjSQ==", + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.4.tgz", + "integrity": "sha512-orzA81VqLyIGUEA77YkVA1D+N+nNfl2isJVjjmOyrlxuooZ19ynb+dOlaDTqd/idKRS9lDCSBmtzM+kyCsMnkA==", "dev": true, "license": "ISC" }, @@ -1352,6 +1356,19 @@ "node": ">=4" } }, + "node_modules/environment": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", + "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/es-module-lexer": { "version": "1.5.4", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz", @@ -1449,9 +1466,9 @@ } }, "node_modules/eslint-plugin-jsdoc": { - "version": "48.8.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-48.8.3.tgz", - "integrity": "sha512-AtIvwwW9D17MRkM0Z0y3/xZYaa9mdAvJrkY6fU/HNUwGbmMtHVvK4qRM9CDixGVtfNrQitb8c6zQtdh6cTOvLg==", + "version": "48.10.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-48.10.2.tgz", + "integrity": "sha512-xTkf/MmEeVrTbezc6kDqCJmK9RcseIKo8X4oyoDCMvV4LY8dqrQi8kmfRrv9n0gNBkCclevaOh2Lkmu6Fs8SLg==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -1460,6 +1477,7 @@ "comment-parser": "1.4.1", "debug": "^4.3.5", "escape-string-regexp": "^4.0.0", + "espree": "^10.1.0", "esquery": "^1.6.0", "parse-imports": "^2.1.1", "semver": "^7.6.3", @@ -1473,6 +1491,37 @@ "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0" } }, + "node_modules/eslint-plugin-jsdoc/node_modules/eslint-visitor-keys": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", + "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-plugin-jsdoc/node_modules/espree": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.1.0.tgz", + "integrity": "sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.12.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/eslint-scope": { "version": "7.2.2", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", @@ -1979,9 +2028,9 @@ } }, "node_modules/husky": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.2.tgz", - "integrity": "sha512-1/aDMXZdhr1VdJJTLt6e7BipM0Jd9qkpubPiIplon1WmCeOy3nnzsCMeBqS9AsL5ioonl8F8y/F2CLOmk19/Pw==", + "version": "9.1.4", + "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.4.tgz", + "integrity": "sha512-bho94YyReb4JV7LYWRWxZ/xr6TtOTt8cMfmQ39MQYJ7f/YE268s3GdghGwi+y4zAeqewE5zYLvuhV0M0ijsDEA==", "dev": true, "license": "MIT", "bin": { @@ -2366,16 +2415,16 @@ } }, "node_modules/listr2": { - "version": "8.2.3", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.2.3.tgz", - "integrity": "sha512-Lllokma2mtoniUOS94CcOErHWAug5iu7HOmDrvWgpw8jyQH2fomgB+7lZS4HWZxytUuQwkGOwe49FvwVaA85Xw==", + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.2.4.tgz", + "integrity": "sha512-opevsywziHd3zHCVQGAj8zu+Z3yHNkkoYhWIGnq54RrCVwLz0MozotJEDnKsIBLvkfLGN6BLOyAeRrYI0pKA4g==", "dev": true, "license": "MIT", "dependencies": { "cli-truncate": "^4.0.0", "colorette": "^2.0.20", "eventemitter3": "^5.0.1", - "log-update": "^6.0.0", + "log-update": "^6.1.0", "rfdc": "^1.4.1", "wrap-ansi": "^9.0.0" }, @@ -2424,15 +2473,15 @@ "license": "MIT" }, "node_modules/log-update": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.0.0.tgz", - "integrity": "sha512-niTvB4gqvtof056rRIrTZvjNYE4rCUzO6X/X+kYjd7WFxXeJ0NwEFnRxX6ehkvv3jTwrXnNdtAak5XYZuIyPFw==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz", + "integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==", "dev": true, "license": "MIT", "dependencies": { - "ansi-escapes": "^6.2.0", - "cli-cursor": "^4.0.0", - "slice-ansi": "^7.0.0", + "ansi-escapes": "^7.0.0", + "cli-cursor": "^5.0.0", + "slice-ansi": "^7.1.0", "strip-ansi": "^7.1.0", "wrap-ansi": "^9.0.0" }, @@ -2592,6 +2641,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/mimic-function": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", + "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/minimatch": { "version": "9.0.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", @@ -3043,55 +3105,38 @@ } }, "node_modules/restore-cursor": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz", - "integrity": "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", + "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", "dev": true, "license": "MIT", "dependencies": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/restore-cursor/node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/restore-cursor/node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", "dev": true, "license": "MIT", "dependencies": { - "mimic-fn": "^2.1.0" + "mimic-function": "^5.0.0" }, "engines": { - "node": ">=6" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/restore-cursor/node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true, - "license": "ISC" - }, "node_modules/reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", @@ -3702,9 +3747,9 @@ } }, "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "version": "6.11.1", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.11.1.tgz", + "integrity": "sha512-mIDEX2ek50x0OlRgxryxsenE5XaQD4on5U2inY7RApK3SOJpofyw7uW2AyfMKkhAxXIceo2DeWGVGwyvng1GNQ==", "dev": true, "license": "MIT" }, diff --git a/package.json b/package.json index dea9681..099dab4 100644 --- a/package.json +++ b/package.json @@ -28,22 +28,30 @@ ] }, "peerDependencies": { - "@highcharts/dashboards": "^2.2.0" + "@highcharts/dashboards": "^2.2.0", + "highcharts": ">=11.4.0" }, "scripts": { - "build": "npm run webpack && npm run build:prepare && npm run build:pack && npm run build:cleanup", - "build:prepare": "mkdir -p build/package/ && cp -R code/* LICENSE.md README.md build/package/ && cp package-build.json build/package/package.json", + "build": "npm run webpack && npm run build:prepare && npm run build:copy && npm run build:pack && npm run build:cleanup", + "build:prepare": "rm -rf build/ ; mkdir -p build/package/", + "build:copy": "cp -R code/* LICENSE.md README.md build/package/ && cp package-build.json build/package/package.json", "build:pack": "npm pack build/package/ --pack-destination build/", "build:cleanup": "rm -rf build/package/", "demos": "npm run webpack && npm run demos:server", "demos:server": "(sleep 1 ; open http://localhost:8080) & python3 -m http.server --bind localhost 8080", "prepare": "rm -rf '.husky/_' ; husky", - "scripts": "tsc -p src/", + "scripts": "rm -rf code/ ; tsc -p src/", + "reset": "rm -rf bin/ build/ code/ node_modules/ ; npm i", "test": "npm run test:prepare", "test:morningstar": "npx -y newman run --bail tmp/Collection.json -e tmp/Environment.json", "test:precommit": "npm run test", - "test:prepare": "npm run webpack", + "test:prepare": "npm run build", + "test:unit-tests": "ts-node test/unit-tests/ts-run", "watch": "tsc -p src/ -w", - "webpack": "npm run scripts && webpack" + "webpack": "npm run scripts && webpack && npm run webpack:dts", + "webpack:dts": "npm run webpack:dts:mc && npm run webpack:dts:mrn && npm run webpack:dts:mts", + "webpack:dts:mc": "cp src/webpack.d.ts code/morningstar-connectors.d.ts && cp src/webpack.d.ts code/morningstar-connectors.src.d.ts", + "webpack:dts:mrn": "cp src/webpack.d.ts code/morningstar-rna-news.d.ts && cp src/webpack.d.ts code/morningstar-rna-news.src.d.ts", + "webpack:dts:mts": "cp src/webpack.d.ts code/morningstar-time-series.d.ts && cp src/webpack.d.ts code/morningstar-time-series.src.d.ts" } } diff --git a/src/RNANews/RNANewsConnector.ts b/src/RNANews/RNANewsConnector.ts index a184f54..ad7ef34 100644 --- a/src/RNANews/RNANewsConnector.ts +++ b/src/RNANews/RNANewsConnector.ts @@ -21,6 +21,7 @@ * * */ + import External from '../Shared/External'; import MorningstarConnector from '../Shared/MorningstarConnector'; import MorningstarAPI from '../Shared/MorningstarAPI'; @@ -29,21 +30,74 @@ import RNANewsOptions from './RNANewsOptions'; import RNANewsConverter from './RNANewsConverter'; import RNANewsJSON from './RNANewsJSON'; + +/* * + * + * Functions + * + * */ + + +/** + * If a number is provided, it is treated as a unix timestamp in + * milliseconds and converted to format `yyyy-MM-dd`. + * If a string is provided, it is validated to conform to the format. + * @private + * @param {number | string} date date as a timestamp of formatted string + * @return {string} date formatted as `yyyy-MM-dd`. + */ +function validateAndFormatDate(date: number | string): string { + let timestamp: number; + if (typeof date === 'string') { + // Check if string is a number, likely a timestamp + if (!Number.isNaN(Number(date))) { + timestamp = Number(date); + } else { + const parsedDate = Date.parse(date); + if (Number.isNaN(parsedDate)) { + throw new Error(`The date ${date} is not a valid date.`); + } + timestamp = parsedDate; + } + } else if (typeof date === 'number') { + timestamp = date; + } else { + throw new Error( + 'The provided date is not of type string, nor number.' + ); + } + + return new Date(timestamp) + .toISOString() + .substring(0, 10); +} + + /* * * * Class * * */ -class RNANewsConnector extends MorningstarConnector { + +export class RNANewsConnector extends MorningstarConnector { + + + /* * + * + * Constructor + * + * */ + /** * Constructs an instance of RNANewsConnector. + * * @param {RNANewsOptions} [options] * Options for the connector and converter. */ public constructor( - options: RNANewsOptions + options: RNANewsOptions = {} ) { super(options); @@ -51,6 +105,7 @@ class RNANewsConnector extends MorningstarConnector { this.options = options; } + /* * * * Properties @@ -63,12 +118,14 @@ class RNANewsConnector extends MorningstarConnector { public override readonly options: RNANewsOptions; + /* * * * Functions * * */ + /** * Loads RNANews data from Morningstar. * @@ -96,12 +153,12 @@ class RNANewsConnector extends MorningstarConnector { searchParams.setSecurityOptions([security]); if (startDate) { - const date = RNANewsConnector.validateAndFormatDate(startDate); + const date = validateAndFormatDate(startDate); searchParams.set('startDate', date); } if (endDate) { - const date = RNANewsConnector.validateAndFormatDate(endDate); + const date = validateAndFormatDate(endDate); searchParams.set('endDate', date); } @@ -128,50 +185,10 @@ class RNANewsConnector extends MorningstarConnector { return this; } -} -/* * - * - * Class Namespace - * - * */ - -namespace RNANewsConnector { - /** - * If a number is provided, it is treated as a unix timestamp in - * milliseconds and converted to format `yyyy-MM-dd`. - * If a string is provided, it is validated to conform to the format. - * @private - * @param {number | string} date date as a timestamp of formatted string - * @return {string} date formatted as `yyyy-MM-dd`. - */ - export function validateAndFormatDate(date: number | string): string { - let timestamp: number; - if (typeof date === 'string') { - // Check if string is a number, likely a timestamp - if (!Number.isNaN(Number(date))) { - timestamp = Number(date); - } else { - const parsedDate = Date.parse(date); - if (Number.isNaN(parsedDate)) { - throw new Error(`The date ${date} is not a valid date.`); - } - timestamp = parsedDate; - } - } else if (typeof date === 'number') { - timestamp = date; - } else { - throw new Error( - 'The provided date is not of type string, nor number.' - ); - } - - return new Date(timestamp) - .toISOString() - .substring(0, 10); - } } + /* * * * Registry @@ -186,10 +203,7 @@ declare module '@highcharts/dashboards/es-modules/Data/Connectors/DataConnectorT } -External.DataConnector.registerType( - 'MorningstarRNANews', - RNANewsConnector -); +External.DataConnector.registerType('MorningstarRNANews', RNANewsConnector); /* * diff --git a/src/RNANews/RNANewsConverter.ts b/src/RNANews/RNANewsConverter.ts index f0e4ea9..478a696 100644 --- a/src/RNANews/RNANewsConverter.ts +++ b/src/RNANews/RNANewsConverter.ts @@ -13,30 +13,32 @@ 'use strict'; -import * as External from '../Shared/External'; + /* * * * Imports * * */ +import * as External from '../Shared/External'; import MorningstarConverter from '../Shared/MorningstarConverter'; import RNANewsJSON from './RNANewsJSON'; import { RNANewsConverterOptions } from './RNANewsOptions'; + /* * * * Class * * */ + /** - * Handles parsing and transformation of - * Regulatory News Announcements to a table. + * Handles parsing and transformation of RNA news to a table. * * @private */ -class RNANewsConverter extends MorningstarConverter { +export class RNANewsConverter extends MorningstarConverter { /* * * @@ -44,6 +46,7 @@ class RNANewsConverter extends MorningstarConverter { * * */ + /** * Constructs an instance of the RNANewsConverter. * @@ -51,7 +54,7 @@ class RNANewsConverter extends MorningstarConverter { * Options for the converter. */ constructor( - options?: RNANewsConverterOptions + options: RNANewsConverterOptions = {} ) { super(options); diff --git a/src/RNANews/RNANewsJSON.ts b/src/RNANews/RNANewsJSON.ts index b76b8dd..9a49204 100644 --- a/src/RNANews/RNANewsJSON.ts +++ b/src/RNANews/RNANewsJSON.ts @@ -21,7 +21,8 @@ * * */ -namespace RNANewsJSON { + +export namespace RNANewsJSON { /* * @@ -30,10 +31,13 @@ namespace RNANewsJSON { * * */ + export type RNANewsResponseItem = [id: string, title: string, source: string, type: string]; - + + export type RNANewsItem = [day: number, title: string, source: string, type: string]; + /** * The response JSON for RNANews from Morningstar. */ @@ -56,14 +60,17 @@ namespace RNANewsJSON { items: RNANewsResponseItem[]; } + export type Response = ResponseItem[]; + /* * * * Functions * * */ + export function isResponse( json?: unknown ): json is Response { @@ -88,6 +95,7 @@ namespace RNANewsJSON { ); } + function isRNANewsResponseItem( json?: unknown ): json is RNANewsResponseItem { @@ -99,14 +107,15 @@ namespace RNANewsJSON { ); } + } /* * -* -* Default Export -* -* */ + * + * Default Export + * + * */ export default RNANewsJSON; diff --git a/src/RNANews/RNANewsOptions.ts b/src/RNANews/RNANewsOptions.ts index da660c4..65ce224 100644 --- a/src/RNANews/RNANewsOptions.ts +++ b/src/RNANews/RNANewsOptions.ts @@ -17,10 +17,21 @@ * Imports * * */ + + import type LocalizationOptions from '../Shared/LocalizationOptions'; + import MorningstarOptions, { MorningstarConverterOptions, MorningstarSecurityOptions } from "../Shared/MorningstarOptions"; import RNANewsJSON from './RNANewsJSON'; + +/* * + * + * Declarations + * + * */ + + export interface RNANewsOptions extends RNANewsConverterOptions, MorningstarOptions { /** @@ -54,14 +65,17 @@ export interface RNANewsOptions extends RNANewsConverterOptions, MorningstarOpti } + export interface RNANewsConverterOptions extends MorningstarConverterOptions { json?: RNANewsJSON.Response } + /* * * * Default Export * * */ + export default RNANewsOptions; diff --git a/src/RNANews/index.ts b/src/RNANews/index.ts index 801111b..f0ed5c4 100644 --- a/src/RNANews/index.ts +++ b/src/RNANews/index.ts @@ -22,7 +22,6 @@ * */ -import RNANewsConverter from "./RNANewsConverter"; import RNANewsConnector from "./RNANewsConnector"; @@ -33,8 +32,9 @@ import RNANewsConnector from "./RNANewsConnector"; * */ -export * from './RNANewsConverter'; export * from './RNANewsConnector'; +export * from './RNANewsConverter'; +export * from './RNANewsOptions'; /* * @@ -44,7 +44,4 @@ export * from './RNANewsConnector'; * */ -export default { - RNANewsConverter, - RNANewsConnector -}; +export default RNANewsConnector; diff --git a/src/TimeSeries/Converters/CumulativeReturnSeriesConverter.ts b/src/TimeSeries/Converters/CumulativeReturnSeriesConverter.ts index 2b9c2a2..0663d9e 100644 --- a/src/TimeSeries/Converters/CumulativeReturnSeriesConverter.ts +++ b/src/TimeSeries/Converters/CumulativeReturnSeriesConverter.ts @@ -59,7 +59,7 @@ export class CumulativeReturnSeriesConverter extends MorningstarConverter { public constructor( - options?: CumulativeReturnSeriesOptions + options: CumulativeReturnSeriesOptions = { type: 'CumulativeReturn' } ) { super(options); @@ -76,6 +76,7 @@ export class CumulativeReturnSeriesConverter extends MorningstarConverter { public override readonly options: Required; + /* * * * Functions diff --git a/src/TimeSeries/Converters/DividendSeriesConverter.ts b/src/TimeSeries/Converters/DividendSeriesConverter.ts index 9f39624..ae3ecfe 100644 --- a/src/TimeSeries/Converters/DividendSeriesConverter.ts +++ b/src/TimeSeries/Converters/DividendSeriesConverter.ts @@ -60,7 +60,7 @@ export class DividendSeriesConverter extends MorningstarConverter { public constructor( - options?: DividendSeriesOptions + options: DividendSeriesOptions = { type: 'Dividend' } ) { super(options); @@ -77,6 +77,7 @@ export class DividendSeriesConverter extends MorningstarConverter { public override readonly options: Required; + /* * * * Functions diff --git a/src/TimeSeries/Converters/GrowthSeriesConverter.ts b/src/TimeSeries/Converters/GrowthSeriesConverter.ts index c21de74..78323fc 100644 --- a/src/TimeSeries/Converters/GrowthSeriesConverter.ts +++ b/src/TimeSeries/Converters/GrowthSeriesConverter.ts @@ -59,7 +59,7 @@ export class GrowthSeriesConverter extends MorningstarConverter { public constructor( - options?: GrowthSeriesOptions + options: GrowthSeriesOptions = { type: 'Growth' } ) { super(options); @@ -76,6 +76,7 @@ export class GrowthSeriesConverter extends MorningstarConverter { public override readonly options: Required; + /* * * * Functions diff --git a/src/TimeSeries/Converters/RatingSeriesConverter.ts b/src/TimeSeries/Converters/RatingSeriesConverter.ts index 17fadf7..623fcab 100644 --- a/src/TimeSeries/Converters/RatingSeriesConverter.ts +++ b/src/TimeSeries/Converters/RatingSeriesConverter.ts @@ -59,7 +59,7 @@ export class RatingSeriesConverter extends MorningstarConverter { public constructor( - options?: RatingSeriesOptions + options: RatingSeriesOptions = { type: 'Rating' } ) { super(options); @@ -76,6 +76,7 @@ export class RatingSeriesConverter extends MorningstarConverter { public override readonly options: Required; + /* * * * Functions diff --git a/src/TimeSeries/TimeSeriesConnector.ts b/src/TimeSeries/TimeSeriesConnector.ts index 7842866..126e762 100644 --- a/src/TimeSeries/TimeSeriesConnector.ts +++ b/src/TimeSeries/TimeSeriesConnector.ts @@ -41,7 +41,7 @@ import TimeSeriesRatingConverter from './Converters/RatingSeriesConverter'; * */ -class TimeSeriesConnector extends MorningstarConnector { +export class TimeSeriesConnector extends MorningstarConnector { /* * @@ -167,10 +167,7 @@ declare module '@highcharts/dashboards/es-modules/Data/Connectors/DataConnectorT } -External.DataConnector.registerType( - 'MorningstarTimeSeries', - TimeSeriesConnector -); +External.DataConnector.registerType('MorningstarTimeSeries', TimeSeriesConnector); /* * diff --git a/src/TimeSeries/index.ts b/src/TimeSeries/index.ts index 4a1ec06..b99f25d 100644 --- a/src/TimeSeries/index.ts +++ b/src/TimeSeries/index.ts @@ -33,8 +33,8 @@ import TimeSeriesConnector from './TimeSeriesConnector'; export * from './TimeSeriesConnector'; -export * from './TimeSeriesOptions'; export * as TimeSeriesConverters from './Converters/index'; +export * from './TimeSeriesOptions'; /* * diff --git a/src/index.ts b/src/index.ts index 55eb171..451845c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -22,7 +22,7 @@ * */ -import MorningstarAPI from './Shared/MorningstarAPI'; +import * as Shared from './Shared/index'; import TimeSeries from './TimeSeries/index'; import RNANews from './RNANews/index'; @@ -35,8 +35,8 @@ import RNANews from './RNANews/index'; export * as Shared from './Shared/index'; -export * as TimeSeries from './TimeSeries/index'; -export * as RNANews from './RNANews/index'; +export * from './TimeSeries/index'; +export * from './RNANews/index'; /* * @@ -47,7 +47,7 @@ export * as RNANews from './RNANews/index'; export default { - MorningstarAPI, + Shared, TimeSeries, RNANews }; diff --git a/src/webpack.d.ts b/src/webpack.d.ts new file mode 100644 index 0000000..bbebe9f --- /dev/null +++ b/src/webpack.d.ts @@ -0,0 +1,5 @@ +import MorningstarConnectors from './es-modules/index'; + +export * from './es-modules/index'; + +export default MorningstarConnectors; diff --git a/tsconfig.json b/tsconfig.json index b39c881..5bc17ad 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -116,7 +116,7 @@ // these options are overrides used only by ts-node // same as the --compilerOptions flag and the TS_NODE_COMPILER_OPTIONS environment variable "compilerOptions": { - "module": "commonjs" + "module": "CommonJS" } } } diff --git a/webpack.config.ts b/webpack.config.ts index 37924d9..d9d093d 100644 --- a/webpack.config.ts +++ b/webpack.config.ts @@ -102,7 +102,7 @@ const webpacks: Array = [ }, // Morningstar RNA news - /*{ + { ...sharedConfiguration, // Path to the main file @@ -124,7 +124,7 @@ const webpacks: Array = [ path: Path.resolve(projectFolder, targetFolder), }, - },*/ + }, // Morningstar time series { ...sharedConfiguration, From 72434bf7903e3daafa055252a39c6fb2d0545282 Mon Sep 17 00:00:00 2001 From: bre1470 <40056287+bre1470@users.noreply.github.com> Date: Thu, 1 Aug 2024 18:49:47 +0200 Subject: [PATCH 02/10] CI: Added initial unit-tests. --- .eslintrc | 5 +- .github/workflows/tests.yml | 25 +- package-lock.json | 459 ++++++++++++++++++++ package.json | 8 +- src/Shared/External.ts | 30 +- src/tsconfig.json | 1 + test/unit-tests/TimeSeries/dividend.test.ts | 21 + test/unit-tests/runtime.ts | 148 +++++++ tsconfig.json | 2 +- 9 files changed, 675 insertions(+), 24 deletions(-) create mode 100644 test/unit-tests/TimeSeries/dividend.test.ts create mode 100644 test/unit-tests/runtime.ts diff --git a/.eslintrc b/.eslintrc index f7894ca..3ab7051 100644 --- a/.eslintrc +++ b/.eslintrc @@ -13,5 +13,8 @@ "brackets", "jsdoc", "@typescript-eslint" - ] + ], + "rules": { + "@typescript-eslint/restrict-plus-operands": 0 + } } diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 62d8186..0e5ae1d 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -6,8 +6,25 @@ on: - 'main' jobs: - test-webpack: - name: Test Webpack + + test-distribution: + name: Test build + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 'lts/*' + cache: 'npm' + + - name: Install dependencies + run: npm install + + - name: Build distribution file + run: npm run build + + test-unit-tests: + name: Test unit-tests runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -19,5 +36,5 @@ jobs: - name: Install dependencies run: npm install - - name: Compile Webpack - run: npm run webpack + - name: Run unit-tests + run: npm test diff --git a/package-lock.json b/package-lock.json index 822e318..8562629 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,11 +9,13 @@ "version": "0.0.1-dev", "license": "UNLICENSED", "devDependencies": { + "@types/jsdom": "^21.1.7", "@typescript-eslint/eslint-plugin": "^7.17.0", "eslint": "^8.56.0", "eslint-plugin-brackets": "^0.1.3", "eslint-plugin-jsdoc": "^48.8.3", "husky": "^9.1.2", + "jsdom": "^24.1.1", "lint-staged": "^15.2.7", "ts-node": "^10.9.2", "typescript": "^5.5.4", @@ -413,6 +415,18 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/jsdom": { + "version": "21.1.7", + "resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-21.1.7.tgz", + "integrity": "sha512-yOriVnggzrnQ3a9OKOCxaVuSug3w3/SbOj5i7VwXWZEyUNl3bLF9V3MfxGbZKuwqJOQyRfqXyROBB1CoZLFWzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/tough-cookie": "*", + "parse5": "^7.0.0" + } + }, "node_modules/@types/json-schema": { "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", @@ -430,6 +444,13 @@ "undici-types": "~6.11.1" } }, + "node_modules/@types/tough-cookie": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz", + "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==", + "dev": true, + "license": "MIT" + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "7.18.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.18.0.tgz", @@ -899,6 +920,19 @@ "node": ">=0.4.0" } }, + "node_modules/agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -1002,6 +1036,13 @@ "node": ">=8" } }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true, + "license": "MIT" + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -1205,6 +1246,19 @@ "dev": true, "license": "MIT" }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/commander": { "version": "12.1.0", "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", @@ -1254,6 +1308,40 @@ "node": ">= 8" } }, + "node_modules/cssstyle": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.0.1.tgz", + "integrity": "sha512-8ZYiJ3A/3OkDd093CBT/0UKDWry7ak4BdPTFP2+QEP7cmhouyq/Up709ASSj2cK02BbZiMgk7kYjZNS4QP5qrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "rrweb-cssom": "^0.6.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/cssstyle/node_modules/rrweb-cssom": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz", + "integrity": "sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/data-urls": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", + "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/debug": { "version": "4.3.6", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", @@ -1272,6 +1360,13 @@ } } }, + "node_modules/decimal.js": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", + "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==", + "dev": true, + "license": "MIT" + }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -1279,6 +1374,16 @@ "dev": true, "license": "MIT" }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/diff": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", @@ -1343,6 +1448,19 @@ "node": ">=10.13.0" } }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/envinfo": { "version": "7.13.0", "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.13.0.tgz", @@ -1827,6 +1945,21 @@ "dev": true, "license": "ISC" }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dev": true, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -2017,6 +2150,47 @@ "license": "https://www.highcharts.com/license", "peer": true }, + "node_modules/html-encoding-sniffer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", + "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-encoding": "^3.1.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", + "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/human-signals": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", @@ -2043,6 +2217,19 @@ "url": "https://github.com/sponsors/typicode" } }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/ignore": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", @@ -2214,6 +2401,13 @@ "node": ">=0.10.0" } }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true, + "license": "MIT" + }, "node_modules/is-stream": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", @@ -2298,6 +2492,47 @@ "node": ">=12.0.0" } }, + "node_modules/jsdom": { + "version": "24.1.1", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-24.1.1.tgz", + "integrity": "sha512-5O1wWV99Jhq4DV7rCLIoZ/UIhyQeDR7wHVyZAHAshbrvZsLs+Xzz7gtwnlJTJDjleiTKh54F4dXrX70vJQTyJQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssstyle": "^4.0.1", + "data-urls": "^5.0.0", + "decimal.js": "^10.4.3", + "form-data": "^4.0.0", + "html-encoding-sniffer": "^4.0.0", + "http-proxy-agent": "^7.0.2", + "https-proxy-agent": "^7.0.5", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.12", + "parse5": "^7.1.2", + "rrweb-cssom": "^0.7.1", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.1.4", + "w3c-xmlserializer": "^5.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^3.1.1", + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0", + "ws": "^8.18.0", + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "canvas": "^2.11.2" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, "node_modules/json-buffer": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", @@ -2727,6 +2962,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/nwsapi": { + "version": "2.2.12", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.12.tgz", + "integrity": "sha512-qXDmcVlZV4XRtKFzddidpfVP4oMSGhga+xdMc25mv8kaLUHtgzCDhUxkrN8exkGdTlLNaXj7CV3GtON7zuGZ+w==", + "dev": true, + "license": "MIT" + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -2840,6 +3082,19 @@ "node": ">= 18" } }, + "node_modules/parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "entities": "^4.4.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -2999,6 +3254,13 @@ "node": ">= 0.8.0" } }, + "node_modules/psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", + "dev": true, + "license": "MIT" + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -3009,6 +3271,13 @@ "node": ">=6" } }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "dev": true, + "license": "MIT" + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -3053,6 +3322,13 @@ "node": ">= 10.13.0" } }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true, + "license": "MIT" + }, "node_modules/resolve": { "version": "1.22.8", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", @@ -3172,6 +3448,13 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/rrweb-cssom": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.7.1.tgz", + "integrity": "sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==", + "dev": true, + "license": "MIT" + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -3217,6 +3500,26 @@ ], "license": "MIT" }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "license": "MIT" + }, + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "dev": true, + "license": "ISC", + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } + }, "node_modules/schema-utils": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", @@ -3523,6 +3826,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true, + "license": "MIT" + }, "node_modules/synckit": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.1.tgz", @@ -3642,6 +3952,35 @@ "node": ">=8.0" } }, + "node_modules/tough-cookie": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz", + "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tr46": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz", + "integrity": "sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/ts-api-utils": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", @@ -3753,6 +4092,16 @@ "dev": true, "license": "MIT" }, + "node_modules/universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, "node_modules/update-browserslist-db": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", @@ -3794,6 +4143,17 @@ "punycode": "^2.1.0" } }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, "node_modules/v8-compile-cache-lib": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", @@ -3801,6 +4161,19 @@ "dev": true, "license": "MIT" }, + "node_modules/w3c-xmlserializer": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", + "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/watchpack": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.1.tgz", @@ -3815,6 +4188,16 @@ "node": ">=10.13.0" } }, + "node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + } + }, "node_modules/webpack": { "version": "5.93.0", "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.93.0.tgz", @@ -3968,6 +4351,43 @@ "node": ">=4.0" } }, + "node_modules/whatwg-encoding": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", + "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-mimetype": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", + "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-url": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.0.0.tgz", + "integrity": "sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tr46": "^5.0.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -4068,6 +4488,45 @@ "dev": true, "license": "ISC" }, + "node_modules/ws": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xml-name-validator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", + "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true, + "license": "MIT" + }, "node_modules/yaml": { "version": "2.4.5", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.5.tgz", diff --git a/package.json b/package.json index 099dab4..cc2e143 100644 --- a/package.json +++ b/package.json @@ -12,10 +12,12 @@ "types": "code/es-modules/index.d.ts", "devDependencies": { "@typescript-eslint/eslint-plugin": "^7.17.0", + "@types/jsdom": "^21.1.7", "eslint": "^8.56.0", "eslint-plugin-brackets": "^0.1.3", "eslint-plugin-jsdoc": "^48.8.3", "husky": "^9.1.2", + "jsdom": "^24.1.1", "lint-staged": "^15.2.7", "ts-node": "^10.9.2", "typescript": "^5.5.4", @@ -42,11 +44,11 @@ "prepare": "rm -rf '.husky/_' ; husky", "scripts": "rm -rf code/ ; tsc -p src/", "reset": "rm -rf bin/ build/ code/ node_modules/ ; npm i", - "test": "npm run test:prepare", + "test": "npm run test:prepare && npm run test:unit-tests", "test:morningstar": "npx -y newman run --bail tmp/Collection.json -e tmp/Environment.json", "test:precommit": "npm run test", - "test:prepare": "npm run build", - "test:unit-tests": "ts-node test/unit-tests/ts-run", + "test:prepare": "npm run webpack", + "test:unit-tests": "ts-node test/unit-tests/runtime", "watch": "tsc -p src/ -w", "webpack": "npm run scripts && webpack && npm run webpack:dts", "webpack:dts": "npm run webpack:dts:mc && npm run webpack:dts:mrn && npm run webpack:dts:mts", diff --git a/src/Shared/External.ts b/src/Shared/External.ts index 8a69429..4b1ac3a 100644 --- a/src/Shared/External.ts +++ b/src/Shared/External.ts @@ -22,9 +22,8 @@ * */ -import type DataConverterType from '@highcharts/dashboards/es-modules/Data/Converters/DataConverter'; - -import * as Dashboards from '@highcharts/dashboards'; +import _DataConverter from '@highcharts/dashboards/es-modules/Data/Converters/DataConverter'; +import * as _Dashboards from '@highcharts/dashboards'; /* * @@ -34,17 +33,19 @@ import * as Dashboards from '@highcharts/dashboards'; * */ -export type DataConnector = Dashboards.DataConnector; +export type DataConnector = _Dashboards.DataConnector; + + +export type DataConnectorOptions = Partial<_Dashboards.DataConnector.UserOptions>; -export type DataConnectorOptions = - Partial; -export type DataConveter = DataConverterType; +export type DataConveter = _DataConverter; -export type DataConverterOptions = Partial; +export type DataConverterOptions = Partial<_DataConverter.Options>; -export type DataTable = Dashboards.DataTable; + +export type DataTable = _Dashboards.DataTable; /* * @@ -54,14 +55,13 @@ export type DataTable = Dashboards.DataTable; * */ -export const DataConnector = Dashboards.DataConnector; +export const DataConnector = _Dashboards.DataConnector; + + +export const DataConverter = _DataConverter; -// @todo simplify -export const DataConverter = - /* eslint-disable-next-line @typescript-eslint/no-unsafe-member-access */ - (Dashboards as any).DataConverter as typeof DataConverterType; -export const DataTable = Dashboards.DataTable; +export const DataTable = _Dashboards.DataTable; /* * diff --git a/src/tsconfig.json b/src/tsconfig.json index 18c5991..2af25df 100644 --- a/src/tsconfig.json +++ b/src/tsconfig.json @@ -7,6 +7,7 @@ "noImplicitReturns": true, "noImplicitThis": true, "sourceMap": true, + "module": "ES2020", "outDir": "../code/es-modules/", "target": "ES2020", "lib": [ diff --git a/test/unit-tests/TimeSeries/dividend.test.ts b/test/unit-tests/TimeSeries/dividend.test.ts new file mode 100644 index 0000000..74bbe8d --- /dev/null +++ b/test/unit-tests/TimeSeries/dividend.test.ts @@ -0,0 +1,21 @@ +import * as Assert from 'node:assert/strict'; +import * as MorningstarConnectors from '../../../code/morningstar-connectors.src'; + +export function dividend_load( + access: MorningstarConnectors.Shared.MorningstarAccessOptions +) { + const connector = new MorningstarConnectors.TimeSeriesConnector({ + api: { + access + }, + series: { + type: 'Dividend' + } + }); + + Assert.ok( + connector instanceof MorningstarConnectors.TimeSeriesConnector, + 'TimeSeries connector should be instance of expected class.' + ); + +} diff --git a/test/unit-tests/runtime.ts b/test/unit-tests/runtime.ts new file mode 100644 index 0000000..a48065f --- /dev/null +++ b/test/unit-tests/runtime.ts @@ -0,0 +1,148 @@ +/* * + * + * (c) 2009-2024 Highsoft AS + * + * License: www.highcharts.com/license + * + * This should be run with `npx ts-node`. + * + * Authors: + * - Sophie Bremer + * + * */ + + +'use strict'; + + +/* * + * + * Imports + * + * */ + + +import type { Shared } from '../../code/morningstar-connectors.src'; + +import * as Assert from 'node:assert/strict'; +import * as FS from 'node:fs/promises'; +import * as JSDOM from 'jsdom'; + + +/* * + * + * Constants + * + * */ + + +const access: Shared.MorningstarAccessOptions = { + password: process.env.MORNINGSTAR_PASSWORD, + username: process.env.MORNINGSTAR_USERNAME +}; + + +/* * + * + * Functions + * + * */ + + +function logError( + error: unknown +) { + if (error instanceof Error) { + console.error(error); + } else { + console.error('' + error); + } +} + + +function prepareGlobals() { + const jsdom = new JSDOM.JSDOM(); + const window = jsdom.window; + const originalDispatchEvent = window.dispatchEvent; + + window.dispatchEvent = function (e: Event){ + const event = new window.Event(e.type, e); + return originalDispatchEvent.call(this, event); + }; + + if (!global.Node) { + global.Node = window.Node; + } + + if (!window.Date) { + window.Date = Date; + } + + globalThis.window = window as unknown as typeof globalThis.window; +} + + +async function runUnitTests() { + + prepareGlobals(); + + const failures: Array = []; + const successes: Array = []; + + let test: unknown; + let testCounter = 0; + let unitTests: Record; + + for (let path of await FS.readdir(__dirname, { recursive: true })) { + + if (!path.endsWith('test.ts')) { + continue; + } + + path = './' + path.substring(0, path.length - 3); + unitTests = await import(path) as Record; + + for (const testName of Object.keys(unitTests)) { + + test = unitTests[testName]; + + if (typeof test === 'function') { + + try { + ++testCounter; + test(access); + successes.push(testName); + + } catch (error) { + logError(error); + failures.push(testName); + } + } + } + + } + + console.info( + successes.length, + 'of', + testCounter, + (testCounter === 1 ? 'test' : 'tests'), + 'succeeded.' + ); + + Assert.deepEqual(failures.length, 0, `${failures.length} failed.`); + +} + + +/* * + * + * Runtime + * + * */ + + +runUnitTests().catch(error => { + logError(error); + process.exit(1); +}); diff --git a/tsconfig.json b/tsconfig.json index 5bc17ad..22808ae 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -27,7 +27,7 @@ /* Modules */ // "module": "commonjs", /* Specify what module code is generated. */ - "module": "ES6", + "module": "CommonJS", // "rootDir": "./", /* Specify the root folder within your source files. */ // "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */ "moduleResolution": "node", From 942fc611489c51558e0bd246c097b82b3f052804 Mon Sep 17 00:00:00 2001 From: bre1470 <40056287+bre1470@users.noreply.github.com> Date: Thu, 1 Aug 2024 20:20:08 +0200 Subject: [PATCH 03/10] Improved MorningstarSearchParams. --- src/Shared/MorningstarSearchParams.ts | 71 ++++++++++++++++++--------- src/Shared/MorningstarURL.ts | 9 +++- src/Shared/index.ts | 8 ++- 3 files changed, 62 insertions(+), 26 deletions(-) diff --git a/src/Shared/MorningstarSearchParams.ts b/src/Shared/MorningstarSearchParams.ts index 86c3894..3c53369 100644 --- a/src/Shared/MorningstarSearchParams.ts +++ b/src/Shared/MorningstarSearchParams.ts @@ -44,33 +44,33 @@ export class MorningstarSearchParams extends URLSearchParams { /** - * Sets `id` and `idType` based on given security options. + * Sets the parameter with the given date. * - * @param options - * Security options to set. + * @param name + * Parameter name to set. + * + * @param date + * JavaScript timestamp or date string. * * @return * The modified search parameters as reference. */ - public setSecurityOptions( - options: Array + public setDate( + name: ('endDate'|'startDate'), + date: (number|string) ): MorningstarSearchParams { - let id: string = this.get('id') || ''; - let idType: string = this.get('idType') || ''; - - options = (options instanceof Array ? options : [options]); - - for (const security of options) { - id = (id ? `${id}|${security.id}` : id); - idType = (idType ? `${idType}|${security.idType}` : idType); - } + const dateTime = ( + typeof date === 'number' ? + new Date(date) : + new Date(Date.parse(date)) + ); - this.set('id', id); - this.set('idType', idType); + this.set(name, dateTime.toISOString().substring(0, 10)); return this; } + /** * Sets `languageId` based on given localization options. * @@ -84,13 +84,40 @@ export class MorningstarSearchParams extends URLSearchParams { options: LocalizationOptions ): MorningstarSearchParams { - const { - country, - language - } = options; + this.set( + 'languageId', ( + options.language.toLowerCase() + + '-' + + options.country.toUpperCase() + ) + ); - const languageCultureCode = `${language.toLowerCase()}-${country.toUpperCase()}`; - this.set('languageId', languageCultureCode); + return this; + } + + + /** + * Sets `id` and `idType` based on given security options. + * + * @param options + * Security options to set. + * + * @return + * The modified search parameters as reference. + */ + public setSecurityOptions( + options: Array + ): MorningstarSearchParams { + let id: string = this.get('id') || ''; + let idType: string = this.get('idType') || ''; + + for (const security of options) { + id = (id ? `${id}|${security.id}` : security.id); + idType = (idType ? `${idType}|${security.idType}` : security.idType); + } + + this.set('id', id); + this.set('idType', idType); return this; } diff --git a/src/Shared/MorningstarURL.ts b/src/Shared/MorningstarURL.ts index 940cb72..0a58e0c 100644 --- a/src/Shared/MorningstarURL.ts +++ b/src/Shared/MorningstarURL.ts @@ -53,7 +53,7 @@ export class MorningstarURL extends URL { super(superURL); - this.searchParams = new MorningstarSearchParams(superURL.searchParams); + this._searchParams = new MorningstarSearchParams(superURL.searchParams); } @@ -64,7 +64,12 @@ export class MorningstarURL extends URL { * */ - public override searchParams: MorningstarSearchParams; + public _searchParams: MorningstarSearchParams; + + + public override get searchParams(): MorningstarSearchParams { + return this._searchParams; + } } diff --git a/src/Shared/index.ts b/src/Shared/index.ts index 2a75ba8..66a2f13 100644 --- a/src/Shared/index.ts +++ b/src/Shared/index.ts @@ -23,7 +23,9 @@ import MorningstarAPI from './MorningstarAPI'; -import MorningstarOAuth2 from './MorningstarAccess'; +import MorningstarError from './MorningstarError'; +import MorningstarAccess from './MorningstarAccess'; +import MorningstarRegion from './MorningstarRegion'; /* * @@ -48,5 +50,7 @@ export * from './MorningstarOptions'; export default { MorningstarAPI, - MorningstarOAuth2 + MorningstarError, + MorningstarAccess, + MorningstarRegion }; From 387f09e0803749563c1a2057ce731ba2a220ad50 Mon Sep 17 00:00:00 2001 From: bre1470 <40056287+bre1470@users.noreply.github.com> Date: Thu, 1 Aug 2024 20:23:16 +0200 Subject: [PATCH 04/10] CI: Improved unit-tests runtime. --- .github/workflows/tests.yml | 9 ++++++--- .gitignore | 2 ++ .husky/pre-commit | 2 +- package.json | 9 ++++----- test/README.md | 23 +++++++++++++++++++++++ test/unit-tests/runtime.ts | 22 ++++++++++++++++------ 6 files changed, 52 insertions(+), 15 deletions(-) create mode 100644 test/README.md diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 0e5ae1d..5f3bc26 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -8,7 +8,7 @@ on: jobs: test-distribution: - name: Test build + name: Test distribution runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -20,12 +20,15 @@ jobs: - name: Install dependencies run: npm install - - name: Build distribution file + - name: Build distribution bundle run: npm run build test-unit-tests: name: Test unit-tests runs-on: ubuntu-latest + env: + MORNINGSTAR_PASSWORD: ${{ secrets.MORNINGSTAR_PWD }} + MORNINGSTAR_USERNAME: ${{ secrets.MORNINGSTAR_USERNAME }} steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -37,4 +40,4 @@ jobs: run: npm install - name: Run unit-tests - run: npm test + run: npm test:unit-tests diff --git a/.gitignore b/.gitignore index 13614f4..f665f68 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,5 @@ /code/ /node_modules/ /tmp/ + +/.env diff --git a/.husky/pre-commit b/.husky/pre-commit index cac06fe..b362e3f 100644 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,2 +1,2 @@ npx lint-staged && \ -npm run test:precommit +npm run test diff --git a/package.json b/package.json index cc2e143..8679ccf 100644 --- a/package.json +++ b/package.json @@ -35,20 +35,19 @@ }, "scripts": { "build": "npm run webpack && npm run build:prepare && npm run build:copy && npm run build:pack && npm run build:cleanup", - "build:prepare": "rm -rf build/ ; mkdir -p build/package/", + "build:cleanup": "rm -rf build/package/", "build:copy": "cp -R code/* LICENSE.md README.md build/package/ && cp package-build.json build/package/package.json", "build:pack": "npm pack build/package/ --pack-destination build/", - "build:cleanup": "rm -rf build/package/", + "build:prepare": "rm -rf build/ ; mkdir -p build/package/", "demos": "npm run webpack && npm run demos:server", "demos:server": "(sleep 1 ; open http://localhost:8080) & python3 -m http.server --bind localhost 8080", "prepare": "rm -rf '.husky/_' ; husky", "scripts": "rm -rf code/ ; tsc -p src/", "reset": "rm -rf bin/ build/ code/ node_modules/ ; npm i", - "test": "npm run test:prepare && npm run test:unit-tests", + "test": "npm run test:prepare", "test:morningstar": "npx -y newman run --bail tmp/Collection.json -e tmp/Environment.json", - "test:precommit": "npm run test", "test:prepare": "npm run webpack", - "test:unit-tests": "ts-node test/unit-tests/runtime", + "test:unit-tests": "npm run test:prepare && node -r ts-node/register --env-file .env test/unit-tests/runtime", "watch": "tsc -p src/ -w", "webpack": "npm run scripts && webpack && npm run webpack:dts", "webpack:dts": "npm run webpack:dts:mc && npm run webpack:dts:mrn && npm run webpack:dts:mts", diff --git a/test/README.md b/test/README.md new file mode 100644 index 0000000..b67db14 --- /dev/null +++ b/test/README.md @@ -0,0 +1,23 @@ +Morningstar Connectors Tests +============================ + +This folder contains all tests related to the Highcharts Dashboards connectors. + + + +Configuration +------------- + +You have to define the Morningstar credentials to be able to run the tests. + +1. Create in your working folder a `.env` file. + +2. Add the following content with your Morningstar credentials. + ``` Shell + MORNINGSTAR_PASSWORD="password123" + MORNINGSTAR_USERNAME="username123" + ``` + +3. Now you can run the tests with: + + - `npm run test:unit-tests` diff --git a/test/unit-tests/runtime.ts b/test/unit-tests/runtime.ts index a48065f..e19762d 100644 --- a/test/unit-tests/runtime.ts +++ b/test/unit-tests/runtime.ts @@ -36,9 +36,12 @@ import * as JSDOM from 'jsdom'; * */ -const access: Shared.MorningstarAccessOptions = { - password: process.env.MORNINGSTAR_PASSWORD, - username: process.env.MORNINGSTAR_USERNAME +const api: Shared.MorningstarAPIOptions = { + access: { + password: process.env.MORNINGSTAR_PASSWORD, + username: process.env.MORNINGSTAR_USERNAME + }, + url: 'https://www.emea-api.morningstar.com' }; @@ -70,6 +73,8 @@ function prepareGlobals() { return originalDispatchEvent.call(this, event); }; + window.fetch = fetch; + if (!global.Node) { global.Node = window.Node; } @@ -89,8 +94,9 @@ async function runUnitTests() { const failures: Array = []; const successes: Array = []; - let test: unknown; let testCounter = 0; + + let test: unknown; let unitTests: Record; for (let path of await FS.readdir(__dirname, { recursive: true })) { @@ -110,7 +116,7 @@ async function runUnitTests() { try { ++testCounter; - test(access); + await test(api); successes.push(testName); } catch (error) { @@ -130,7 +136,11 @@ async function runUnitTests() { 'succeeded.' ); - Assert.deepEqual(failures.length, 0, `${failures.length} failed.`); + Assert.deepEqual( + failures.length, + 0, + `${failures.length} ${(failures.length === 1 ? 'test' : 'tests')} failed.` + ); } From e4d43013d9d9c0d79ef415cf7957097bae5fa19d Mon Sep 17 00:00:00 2001 From: bre1470 <40056287+bre1470@users.noreply.github.com> Date: Thu, 1 Aug 2024 20:24:54 +0200 Subject: [PATCH 05/10] CI: Fixed unit-tests action. --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 5f3bc26..99a8db7 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -40,4 +40,4 @@ jobs: run: npm install - name: Run unit-tests - run: npm test:unit-tests + run: npm run test:unit-tests From e026c1b63c245b80a98f04bf2ae011bc734a2b7b Mon Sep 17 00:00:00 2001 From: bre1470 <40056287+bre1470@users.noreply.github.com> Date: Thu, 1 Aug 2024 20:35:02 +0200 Subject: [PATCH 06/10] Tools: Simplified test scripts. --- .github/workflows/tests.yml | 9 ++++++--- .husky/pre-commit | 2 +- package.json | 5 ++--- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 99a8db7..e6b08c6 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -7,7 +7,7 @@ on: jobs: - test-distribution: + test_distribution: name: Test distribution runs-on: ubuntu-latest steps: @@ -23,7 +23,7 @@ jobs: - name: Build distribution bundle run: npm run build - test-unit-tests: + test_unit-tests: name: Test unit-tests runs-on: ubuntu-latest env: @@ -39,5 +39,8 @@ jobs: - name: Install dependencies run: npm install + - name: Build webpack + run: npm run webpack + - name: Run unit-tests - run: npm run test:unit-tests + run: npx ts-node test/unit-tests/runtime diff --git a/.husky/pre-commit b/.husky/pre-commit index b362e3f..fd37f69 100644 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,2 +1,2 @@ npx lint-staged && \ -npm run test +npm run webpack diff --git a/package.json b/package.json index 8679ccf..cab587e 100644 --- a/package.json +++ b/package.json @@ -44,10 +44,9 @@ "prepare": "rm -rf '.husky/_' ; husky", "scripts": "rm -rf code/ ; tsc -p src/", "reset": "rm -rf bin/ build/ code/ node_modules/ ; npm i", - "test": "npm run test:prepare", + "test": "npm run test:unit-tests", "test:morningstar": "npx -y newman run --bail tmp/Collection.json -e tmp/Environment.json", - "test:prepare": "npm run webpack", - "test:unit-tests": "npm run test:prepare && node -r ts-node/register --env-file .env test/unit-tests/runtime", + "test:unit-tests": "npm run webpack && node -r ts-node/register --env-file .env test/unit-tests/runtime", "watch": "tsc -p src/ -w", "webpack": "npm run scripts && webpack && npm run webpack:dts", "webpack:dts": "npm run webpack:dts:mc && npm run webpack:dts:mrn && npm run webpack:dts:mts", From 578d40a174022553f8435926b7438e60145967b6 Mon Sep 17 00:00:00 2001 From: bre1470 <40056287+bre1470@users.noreply.github.com> Date: Fri, 2 Aug 2024 15:27:57 +0200 Subject: [PATCH 07/10] Added request to MorningstarError and improved test runtime. --- .github/workflows/tests.yml | 2 +- package.json | 2 +- src/Shared/MorningstarError.ts | 5 ++ test/unit-tests/Shared/api.test.ts | 14 ++++ test/unit-tests/runtime.ts | 107 +++++++++++++++++++++-------- 5 files changed, 98 insertions(+), 32 deletions(-) create mode 100644 test/unit-tests/Shared/api.test.ts diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index e6b08c6..c084f4f 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -39,7 +39,7 @@ jobs: - name: Install dependencies run: npm install - - name: Build webpack + - name: Build webpack bundles run: npm run webpack - name: Run unit-tests diff --git a/package.json b/package.json index cab587e..ee9ad96 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "reset": "rm -rf bin/ build/ code/ node_modules/ ; npm i", "test": "npm run test:unit-tests", "test:morningstar": "npx -y newman run --bail tmp/Collection.json -e tmp/Environment.json", - "test:unit-tests": "npm run webpack && node -r ts-node/register --env-file .env test/unit-tests/runtime", + "test:unit-tests": "npm run webpack && ts-node test/unit-tests/runtime", "watch": "tsc -p src/ -w", "webpack": "npm run scripts && webpack && npm run webpack:dts", "webpack:dts": "npm run webpack:dts:mc && npm run webpack:dts:mrn && npm run webpack:dts:mts", diff --git a/src/Shared/MorningstarError.ts b/src/Shared/MorningstarError.ts index 8b1b83c..ed5c2ff 100644 --- a/src/Shared/MorningstarError.ts +++ b/src/Shared/MorningstarError.ts @@ -33,6 +33,7 @@ export class MorningstarError extends Error { public constructor ( + request: RequestInit, response: Response ) { super( @@ -41,6 +42,7 @@ export class MorningstarError extends Error { 'Unknown Error' ); + this.request = request; this.response = response; } @@ -52,6 +54,9 @@ export class MorningstarError extends Error { * */ + public readonly request: RequestInit; + + public readonly response: Response; diff --git a/test/unit-tests/Shared/api.test.ts b/test/unit-tests/Shared/api.test.ts new file mode 100644 index 0000000..895657a --- /dev/null +++ b/test/unit-tests/Shared/api.test.ts @@ -0,0 +1,14 @@ +import * as Assert from 'node:assert/strict'; +import * as MC from '../../../code/morningstar-connectors.src'; + +export async function api_access( + apiOptions: MC.Shared.MorningstarAPIOptions +) { + const api = new MC.Shared.MorningstarAPI(apiOptions); + + Assert.ok( + await api.access.authenticate(), + 'Morningstar API credentials should be valid.' + ); + +} diff --git a/test/unit-tests/runtime.ts b/test/unit-tests/runtime.ts index e19762d..ea3c87d 100644 --- a/test/unit-tests/runtime.ts +++ b/test/unit-tests/runtime.ts @@ -31,35 +31,66 @@ import * as JSDOM from 'jsdom'; /* * * - * Constants + * Functions * * */ -const api: Shared.MorningstarAPIOptions = { - access: { - password: process.env.MORNINGSTAR_PASSWORD, - username: process.env.MORNINGSTAR_USERNAME - }, - url: 'https://www.emea-api.morningstar.com' -}; +async function getAPIOptions(): Promise { + const apiOptions: Shared.MorningstarAPIOptions = { + url: 'https://www.emea-api.morningstar.com' + }; + if ((await FS.lstat('.env')).isFile()) { + process.loadEnvFile('.env'); + } -/* * - * - * Functions - * - * */ + if ( + process.env.MORNINGSTAR_PASSWORD && + process.env.MORNINGSTAR_USERNAME + ) { + apiOptions.access = { + password: process.env.MORNINGSTAR_PASSWORD, + username: process.env.MORNINGSTAR_USERNAME + } + } + + return apiOptions; +} -function logError( +async function logError( error: unknown -) { +): Promise { + if (error instanceof Error) { - console.error(error); + const request = (error as Shared.MorningstarError).request; + const response = (error as Shared.MorningstarError).response; + + // Duck typing to avoid real import before tests + if (response) { + const headers = ( + request.headers instanceof Headers ? + request.headers : + new Headers(request.headers) + ); + + console.error(error.message); + console.error('REQUEST:', new Map(headers.entries())); + console.error('RESPONSE:', await response.text()); + + } else { + + console.error(error); + + } + } else { + console.error('' + error); + } + } @@ -88,18 +119,14 @@ function prepareGlobals() { async function runUnitTests() { - - prepareGlobals(); - const failures: Array = []; const successes: Array = []; - - let testCounter = 0; + const stdout = process.stdout; let test: unknown; let unitTests: Record; - for (let path of await FS.readdir(__dirname, { recursive: true })) { + for (let path of (await FS.readdir(__dirname, { recursive: true })).sort()) { if (!path.endsWith('test.ts')) { continue; @@ -108,31 +135,45 @@ async function runUnitTests() { path = './' + path.substring(0, path.length - 3); unitTests = await import(path) as Record; - for (const testName of Object.keys(unitTests)) { + for (let testName of Object.keys(unitTests).sort()) { test = unitTests[testName]; + testName = testName.replace('_', ' '); if (typeof test === 'function') { try { - ++testCounter; - await test(api); + + stdout.write(`[${new Date().toISOString().substring(0, 19).replace('T', ' ')}]`); + stdout.write(` Test ${testName} ... `); + + await test(await getAPIOptions()); + + stdout.write('success.\n'); + successes.push(testName); } catch (error) { - logError(error); + + stdout.write('failure.\n'); + + await logError(error); + failures.push(testName); + } } } } + const total = successes.length + failures.length; + console.info( successes.length, 'of', - testCounter, - (testCounter === 1 ? 'test' : 'tests'), + total, + (total === 1 ? 'test' : 'tests'), 'succeeded.' ); @@ -152,7 +193,13 @@ async function runUnitTests() { * */ -runUnitTests().catch(error => { - logError(error); +prepareGlobals(); + + +runUnitTests().catch(async error => { + + await logError(error); + process.exit(1); + }); From 7b0928488e4442f9c3a2203aff0638faa8319b31 Mon Sep 17 00:00:00 2001 From: bre1470 <40056287+bre1470@users.noreply.github.com> Date: Fri, 2 Aug 2024 18:24:56 +0200 Subject: [PATCH 08/10] Integrated search params into MorningstarURL. --- src/RNANews/RNANewsConnector.ts | 13 ++- src/Shared/MorningstarAPI.ts | 17 +++- src/Shared/MorningstarSearchParams.ts | 136 -------------------------- src/Shared/MorningstarURL.ts | 84 +++++++++++++--- src/TimeSeries/TimeSeriesConnector.ts | 28 ++++-- src/TimeSeries/TimeSeriesOptions.ts | 12 +++ test/unit-tests/runtime.ts | 27 +++-- 7 files changed, 142 insertions(+), 175 deletions(-) delete mode 100644 src/Shared/MorningstarSearchParams.ts diff --git a/src/RNANews/RNANewsConnector.ts b/src/RNANews/RNANewsConnector.ts index ad7ef34..f380486 100644 --- a/src/RNANews/RNANewsConnector.ts +++ b/src/RNANews/RNANewsConnector.ts @@ -146,20 +146,19 @@ export class RNANewsConnector extends MorningstarConnector { return this; } - const url = new MorningstarURL('timeseries/rna-news'); - const searchParams = url.searchParams; const api = new MorningstarAPI(options.api); + const url = new MorningstarURL('timeseries/rna-news'); - searchParams.setSecurityOptions([security]); + url.setSecuritiesOptions([security]); if (startDate) { const date = validateAndFormatDate(startDate); - searchParams.set('startDate', date); + url.setDate('startDate', date); } if (endDate) { const date = validateAndFormatDate(endDate); - searchParams.set('endDate', date); + url.setDate('endDate', date); } if (maxStories) { @@ -167,11 +166,11 @@ export class RNANewsConnector extends MorningstarConnector { if (!Number.isInteger(numericMaxStories)) { throw new Error(`Expected maxStories to be integer, but is instead ${maxStories}`); } - searchParams.set('maxStories', '' + maxStories); + url.searchParams.set('maxStories', '' + maxStories); } if (localization) { - searchParams.setLocalizationOptions(localization); + url.setLocalizationOptions(localization); } const response = await api.fetch(url); diff --git a/src/Shared/MorningstarAPI.ts b/src/Shared/MorningstarAPI.ts index b304cec..ff242f8 100644 --- a/src/Shared/MorningstarAPI.ts +++ b/src/Shared/MorningstarAPI.ts @@ -119,6 +119,10 @@ export class MorningstarAPI { requestInit: RequestInit = {} ): Promise { + if (url.searchParams.get('outputType') !== 'compactjson') { + url.searchParams.set('outputType', 'json'); + } + const requestDelay = ( this.requestDelay - ((new Date()).getTime() - this.lastRequestTimestamp) @@ -131,7 +135,10 @@ export class MorningstarAPI { this.lastRequestTimestamp = (new Date()).getTime(); - if (this.access.authorized) { + if ( + this.access.authorized || + await this.access.authenticate() + ) { requestInit = this.access.authorizeRequest(requestInit); } @@ -142,11 +149,13 @@ export class MorningstarAPI { } if (response.status >= 400) { - throw new MorningstarError(response); + throw new MorningstarError(requestInit, response); } - if (response.headers.get('Content-Type') !== 'application/json') { - throw new Error('Unexpected data'); + const contentType = response.headers.get('Content-Type'); + + if (contentType !== 'application/json') { + throw new Error(`Unexpected data: ${contentType}`); } const rateLimit = parseInt(response.headers.get('X-RateLimit-Limit') || '0', 10); diff --git a/src/Shared/MorningstarSearchParams.ts b/src/Shared/MorningstarSearchParams.ts deleted file mode 100644 index 3c53369..0000000 --- a/src/Shared/MorningstarSearchParams.ts +++ /dev/null @@ -1,136 +0,0 @@ -/* * - * - * (c) 2009-2024 Highsoft AS - * - * License: www.highcharts.com/license - * - * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!! - * - * Authors: - * - Sophie Bremer - * - * */ - - -'use strict'; - - -/* * - * - * Imports - * - * */ - - -import type { MorningstarSecurityOptions } from './MorningstarOptions'; -import LocalizationOptions from './LocalizationOptions'; - - -/* * - * - * Class - * - * */ - - -export class MorningstarSearchParams extends URLSearchParams { - - - /* * - * - * Functions - * - * */ - - - /** - * Sets the parameter with the given date. - * - * @param name - * Parameter name to set. - * - * @param date - * JavaScript timestamp or date string. - * - * @return - * The modified search parameters as reference. - */ - public setDate( - name: ('endDate'|'startDate'), - date: (number|string) - ): MorningstarSearchParams { - const dateTime = ( - typeof date === 'number' ? - new Date(date) : - new Date(Date.parse(date)) - ); - - this.set(name, dateTime.toISOString().substring(0, 10)); - - return this; - } - - - /** - * Sets `languageId` based on given localization options. - * - * @param options - * Localization options to set. - * - * @return - * The modified search parameters as reference. - */ - public setLocalizationOptions( - options: LocalizationOptions - ): MorningstarSearchParams { - - this.set( - 'languageId', ( - options.language.toLowerCase() + - '-' + - options.country.toUpperCase() - ) - ); - - return this; - } - - - /** - * Sets `id` and `idType` based on given security options. - * - * @param options - * Security options to set. - * - * @return - * The modified search parameters as reference. - */ - public setSecurityOptions( - options: Array - ): MorningstarSearchParams { - let id: string = this.get('id') || ''; - let idType: string = this.get('idType') || ''; - - for (const security of options) { - id = (id ? `${id}|${security.id}` : security.id); - idType = (idType ? `${idType}|${security.idType}` : security.idType); - } - - this.set('id', id); - this.set('idType', idType); - - return this; - } - - -} - - -/* * - * - * Default Export - * - * */ - - -export default MorningstarSearchParams; diff --git a/src/Shared/MorningstarURL.ts b/src/Shared/MorningstarURL.ts index 0a58e0c..7a0e4dc 100644 --- a/src/Shared/MorningstarURL.ts +++ b/src/Shared/MorningstarURL.ts @@ -8,6 +8,7 @@ * * Authors: * - Sophie Bremer + * - Eskil Gjerde Sviggum * * */ @@ -22,7 +23,8 @@ * */ -import MorningstarSearchParams from "./MorningstarSearchParams"; +import type { MorningstarSecurityOptions } from './MorningstarOptions'; +import LocalizationOptions from './LocalizationOptions'; /* * @@ -40,35 +42,87 @@ export class MorningstarURL extends URL { /* * * - * Constructor + * Functions * * */ - public constructor( - url: (string|URL), - base: (string|URL|undefined) = window.location.href - ) { - const superURL = new URL(url, base); + /** + * Sets the parameter with the given date. + * + * @param name + * Parameter name to set. + * + * @param date + * JavaScript timestamp or date string. + * + * @return + * The modified search parameters as reference. + */ + public setDate( + name: ('endDate'|'startDate'), + date: (number|string) + ): void { + const dateTime = ( + typeof date === 'number' ? + new Date(date) : + new Date(Date.parse(date)) + ); + + this.searchParams.set(name, dateTime.toISOString().substring(0, 10)); + + } - super(superURL); - this._searchParams = new MorningstarSearchParams(superURL.searchParams); + /** + * Sets `languageId` based on given localization options. + * + * @param options + * Localization options to set. + * + * @return + * The modified search parameters as reference. + */ + public setLocalizationOptions( + options: LocalizationOptions + ): void { + + this.searchParams.set( + 'languageId', ( + options.language.toLowerCase() + + '-' + + options.country.toUpperCase() + ) + ); + } - /* * + /** + * Sets `id` and `idType` based on given security options. * - * Properties + * @param options + * Security options to set. * - * */ + * @return + * The modified search parameters as reference. + */ + public setSecuritiesOptions( + securities: Array + ): void { + const searchParams = this.searchParams; + let id: string = searchParams.get('id') || ''; + let idType: string = searchParams.get('idType') || ''; - public _searchParams: MorningstarSearchParams; + for (const security of securities) { + id = (id ? `${id}|${security.id}` : security.id); + idType = (idType ? `${idType}|${security.idType}` : security.idType); + } + searchParams.set('id', id); + searchParams.set('idType', idType); - public override get searchParams(): MorningstarSearchParams { - return this._searchParams; } diff --git a/src/TimeSeries/TimeSeriesConnector.ts b/src/TimeSeries/TimeSeriesConnector.ts index 126e762..1c7fca6 100644 --- a/src/TimeSeries/TimeSeriesConnector.ts +++ b/src/TimeSeries/TimeSeriesConnector.ts @@ -63,6 +63,7 @@ export class TimeSeriesConnector extends MorningstarConnector { ...options.converter, ...options.series }); + this.path = 'timeseries/cumulativereturn'; break; case 'Dividend': @@ -70,6 +71,7 @@ export class TimeSeriesConnector extends MorningstarConnector { ...options.converter, ...options.series }); + this.path = 'timeseries/dividend'; break; case 'Growth': @@ -77,6 +79,7 @@ export class TimeSeriesConnector extends MorningstarConnector { ...options.converter, ...options.series }); + this.path = 'timeseries/growth'; break; case 'Rating': @@ -84,6 +87,7 @@ export class TimeSeriesConnector extends MorningstarConnector { ...options.converter, ...options.series }); + this.path = 'timeseries/rating'; break; default: @@ -109,6 +113,9 @@ export class TimeSeriesConnector extends MorningstarConnector { public override readonly options: TimeSeriesOptions; + public readonly path: string; + + /* * * * Functions @@ -118,23 +125,32 @@ export class TimeSeriesConnector extends MorningstarConnector { public override async load(): Promise { const options = this.options; - const securities = options.securities; const currencyId = options.currencyId; + const endDate = options.endDate; + const securities = options.securities; + const startDate = options.startDate; const tax = options.tax; if (securities) { - const url = new MorningstarURL('timeseries/cumulativereturn'); - const searchParams = url.searchParams; const api = new MorningstarAPI(options.api); + const url = new MorningstarURL(this.path, api.baseURL); - searchParams.setSecurityOptions(securities); + url.setSecuritiesOptions(securities); if (currencyId) { - searchParams.set('currencyId', currencyId); + url.searchParams.set('currencyId', currencyId); + } + + if (endDate) { + url.setDate('endDate', endDate); + } + + if (startDate) { + url.setDate('startDate', startDate); } if (tax) { - searchParams.set('tax', tax); + url.searchParams.set('tax', tax); } const response = await api.fetch(url); diff --git a/src/TimeSeries/TimeSeriesOptions.ts b/src/TimeSeries/TimeSeriesOptions.ts index 56a301b..b284722 100644 --- a/src/TimeSeries/TimeSeriesOptions.ts +++ b/src/TimeSeries/TimeSeriesOptions.ts @@ -115,6 +115,12 @@ export interface TimeSeriesOptions extends MorningstarOptions { */ currencyId?: string; + /** + * The end date for the requested securities data. This can be either a + * JavaScript timestamp or a date string. + */ + endDate?: (number|string); + /** * Localization options. */ @@ -130,6 +136,12 @@ export interface TimeSeriesOptions extends MorningstarOptions { */ series?: TimeSeriesType; + /** + * The start date for the requested securities data. This can be either a + * JavaScript timestamp or a date string. + */ + startDate?: (number|string); + /** * Tax option. */ diff --git a/test/unit-tests/runtime.ts b/test/unit-tests/runtime.ts index ea3c87d..c760a79 100644 --- a/test/unit-tests/runtime.ts +++ b/test/unit-tests/runtime.ts @@ -38,7 +38,7 @@ import * as JSDOM from 'jsdom'; async function getAPIOptions(): Promise { const apiOptions: Shared.MorningstarAPIOptions = { - url: 'https://www.emea-api.morningstar.com' + url: 'https://www.emea-api.morningstar.com/ecint/v1/' }; if ((await FS.lstat('.env')).isFile()) { @@ -128,14 +128,16 @@ async function runUnitTests() { for (let path of (await FS.readdir(__dirname, { recursive: true })).sort()) { - if (!path.endsWith('test.ts')) { + if (!path.endsWith('.test.ts')) { continue; } + stdWrite('Start', path.substring(0, path.length - 8), 'tests ...\n'); + path = './' + path.substring(0, path.length - 3); unitTests = await import(path) as Record; - for (let testName of Object.keys(unitTests).sort()) { + for (let testName of Object.keys(unitTests)) { test = unitTests[testName]; testName = testName.replace('_', ' '); @@ -144,18 +146,17 @@ async function runUnitTests() { try { - stdout.write(`[${new Date().toISOString().substring(0, 19).replace('T', ' ')}]`); - stdout.write(` Test ${testName} ... `); + stdWrite('Test', testName, '...'); await test(await getAPIOptions()); - stdout.write('success.\n'); + stdout.write(' OK.\n'); successes.push(testName); } catch (error) { - stdout.write('failure.\n'); + stdout.write(' ERROR.\n'); await logError(error); @@ -186,6 +187,18 @@ async function runUnitTests() { } +function stdWrite( + ...text: Array +): void { + process.stdout.write([ + '[', + new Date().toISOString().substring(0, 19).replace('T', ' '), + '] ', + text.join(' ') + ].join('')); +} + + /* * * * Runtime From fedb0ccdaacfbda41a0333a7e62f9cc5aa05ff74 Mon Sep 17 00:00:00 2001 From: bre1470 <40056287+bre1470@users.noreply.github.com> Date: Fri, 2 Aug 2024 18:49:20 +0200 Subject: [PATCH 09/10] Fixed JSON validation in TimeSeries and improved unit-tests. --- .../Converters/DividendSeriesConverter.ts | 5 +- .../Converters/GrowthSeriesConverter.ts | 2 +- .../Converters/RatingSeriesConverter.ts | 2 +- src/TimeSeries/TimeSeriesJSON.ts | 4 +- .../{api.test.ts => MorningstarAPI.test.ts} | 0 .../TimeSeries/DividendConverter.test.ts | 40 +++++++++++++++ test/unit-tests/TimeSeries/dividend.test.ts | 21 -------- test/unit-tests/runtime.ts | 50 ++++++++++++------- 8 files changed, 78 insertions(+), 46 deletions(-) rename test/unit-tests/Shared/{api.test.ts => MorningstarAPI.test.ts} (100%) create mode 100644 test/unit-tests/TimeSeries/DividendConverter.test.ts delete mode 100644 test/unit-tests/TimeSeries/dividend.test.ts diff --git a/src/TimeSeries/Converters/DividendSeriesConverter.ts b/src/TimeSeries/Converters/DividendSeriesConverter.ts index ae3ecfe..0d59063 100644 --- a/src/TimeSeries/Converters/DividendSeriesConverter.ts +++ b/src/TimeSeries/Converters/DividendSeriesConverter.ts @@ -98,7 +98,8 @@ export class DividendSeriesConverter extends MorningstarConverter { // Validate JSON - if (!TimeSeriesJSON.isResponse(json)) { + if (!TimeSeriesJSON.isTimeSeriesResponse(json)) { + console.log(json); throw new Error('Invalid data'); } @@ -107,7 +108,7 @@ export class DividendSeriesConverter extends MorningstarConverter { const securityIds: Array = []; const sortedDividends: Array = []; - for (const security of json.TimeSeries.Security) { + for (const security of json.Security) { if (!security.DividendSeries) { continue; diff --git a/src/TimeSeries/Converters/GrowthSeriesConverter.ts b/src/TimeSeries/Converters/GrowthSeriesConverter.ts index 78323fc..9a56ac6 100644 --- a/src/TimeSeries/Converters/GrowthSeriesConverter.ts +++ b/src/TimeSeries/Converters/GrowthSeriesConverter.ts @@ -96,7 +96,7 @@ export class GrowthSeriesConverter extends MorningstarConverter { // Validate JSON - if (!TimeSeriesJSON.isTimeSeriesReponse(json)) { + if (!TimeSeriesJSON.isTimeSeriesResponse(json)) { throw new Error('Invalid data'); } diff --git a/src/TimeSeries/Converters/RatingSeriesConverter.ts b/src/TimeSeries/Converters/RatingSeriesConverter.ts index 623fcab..3720b97 100644 --- a/src/TimeSeries/Converters/RatingSeriesConverter.ts +++ b/src/TimeSeries/Converters/RatingSeriesConverter.ts @@ -96,7 +96,7 @@ export class RatingSeriesConverter extends MorningstarConverter { // Validate JSON - if (!TimeSeriesJSON.isTimeSeriesReponse(json)) { + if (!TimeSeriesJSON.isTimeSeriesResponse(json)) { throw new Error('Invalid data'); } diff --git a/src/TimeSeries/TimeSeriesJSON.ts b/src/TimeSeries/TimeSeriesJSON.ts index 2414014..590bc9d 100644 --- a/src/TimeSeries/TimeSeriesJSON.ts +++ b/src/TimeSeries/TimeSeriesJSON.ts @@ -120,7 +120,7 @@ namespace TimeSeriesJSON { !!json && typeof json === 'object' && typeof (json as Response).TimeSeries === 'object' && - isTimeSeriesReponse((json as Response).TimeSeries) + isTimeSeriesResponse((json as Response).TimeSeries) ); } @@ -148,7 +148,7 @@ namespace TimeSeriesJSON { } - export function isTimeSeriesReponse( + export function isTimeSeriesResponse( json?: unknown ): json is TimeSeriesResponse { return ( diff --git a/test/unit-tests/Shared/api.test.ts b/test/unit-tests/Shared/MorningstarAPI.test.ts similarity index 100% rename from test/unit-tests/Shared/api.test.ts rename to test/unit-tests/Shared/MorningstarAPI.test.ts diff --git a/test/unit-tests/TimeSeries/DividendConverter.test.ts b/test/unit-tests/TimeSeries/DividendConverter.test.ts new file mode 100644 index 0000000..2bcc3c7 --- /dev/null +++ b/test/unit-tests/TimeSeries/DividendConverter.test.ts @@ -0,0 +1,40 @@ +import * as Assert from 'node:assert/strict'; +import * as MorningstarConnectors from '../../../code/morningstar-connectors.src'; + +export async function rating_load( + api: MorningstarConnectors.Shared.MorningstarAPIOptions +) { + const connector = new MorningstarConnectors.TimeSeriesConnector({ + api, + currencyId: 'EUR', + endDate: '2020-12-31', + securities: [{ + id: 'F0GBR04S23', + idType: 'MSID' + }], + series: { + type: 'Dividend' + }, + startDate: '2020-01-01' + }); + + Assert.ok( + connector instanceof MorningstarConnectors.TimeSeriesConnector, + 'Connector should be instance of TimeSeries class.' + ); + + Assert.ok( + connector.converter instanceof + MorningstarConnectors.TimeSeriesConverters.DividendSeriesConverter, + 'Converter should be instance of TimeSeries DividendSeriesConverter.' + ); + + await connector.load(); + + Assert.deepStrictEqual( + connector.table.getColumnNames(), + ['Date', connector.options.securities?.[0].id], + 'Connector table should exist of expected columns.' + ); + +} diff --git a/test/unit-tests/TimeSeries/dividend.test.ts b/test/unit-tests/TimeSeries/dividend.test.ts deleted file mode 100644 index 74bbe8d..0000000 --- a/test/unit-tests/TimeSeries/dividend.test.ts +++ /dev/null @@ -1,21 +0,0 @@ -import * as Assert from 'node:assert/strict'; -import * as MorningstarConnectors from '../../../code/morningstar-connectors.src'; - -export function dividend_load( - access: MorningstarConnectors.Shared.MorningstarAccessOptions -) { - const connector = new MorningstarConnectors.TimeSeriesConnector({ - api: { - access - }, - series: { - type: 'Dividend' - } - }); - - Assert.ok( - connector instanceof MorningstarConnectors.TimeSeriesConnector, - 'TimeSeries connector should be instance of expected class.' - ); - -} diff --git a/test/unit-tests/runtime.ts b/test/unit-tests/runtime.ts index c760a79..62f5d58 100644 --- a/test/unit-tests/runtime.ts +++ b/test/unit-tests/runtime.ts @@ -24,8 +24,8 @@ import type { Shared } from '../../code/morningstar-connectors.src'; -import * as Assert from 'node:assert/strict'; import * as FS from 'node:fs/promises'; +import * as FSSync from 'node:fs'; import * as JSDOM from 'jsdom'; @@ -36,12 +36,12 @@ import * as JSDOM from 'jsdom'; * */ -async function getAPIOptions(): Promise { +function getAPIOptions(): Shared.MorningstarAPIOptions { const apiOptions: Shared.MorningstarAPIOptions = { url: 'https://www.emea-api.morningstar.com/ecint/v1/' }; - if ((await FS.lstat('.env')).isFile()) { + if (FSSync.existsSync('.env')) { process.loadEnvFile('.env'); } @@ -148,15 +148,15 @@ async function runUnitTests() { stdWrite('Test', testName, '...'); - await test(await getAPIOptions()); + await test(getAPIOptions()); - stdout.write(' OK.\n'); + stdout.write(' ✅ OK.\n'); successes.push(testName); } catch (error) { - stdout.write(' ERROR.\n'); + stdout.write(' ❌ ERROR.\n'); await logError(error); @@ -170,25 +170,37 @@ async function runUnitTests() { const total = successes.length + failures.length; - console.info( - successes.length, - 'of', - total, - (total === 1 ? 'test' : 'tests'), - 'succeeded.' - ); + if (successes.length === total) { - Assert.deepEqual( - failures.length, - 0, - `${failures.length} ${(failures.length === 1 ? 'test' : 'tests')} failed.` - ); + stdWrite( + '✅', (total === 1 ? 'This' : 'All'), total, + (total === 1 ? 'test' : 'tests'), + 'succeeded.\n' + ); + + } else { + + stdWrite( + '✅', successes.length, 'of', total, + (total === 1 ? 'test' : 'tests'), + 'succeeded.\n' + ); + + stdWrite( + '❌', failures.length, + (failures.length === 1 ? 'test' : 'tests'), + 'failed.\n' + ); + + } + + process.exit(0); } function stdWrite( - ...text: Array + ...text: Array ): void { process.stdout.write([ '[', From ebf813ef9944abbee2b9a9ae0a91258bd9362d44 Mon Sep 17 00:00:00 2001 From: bre1470 <40056287+bre1470@users.noreply.github.com> Date: Fri, 2 Aug 2024 19:04:59 +0200 Subject: [PATCH 10/10] Fixed table rows in TimeSeries converters. --- .../CumulativeReturnSeriesConverter.ts | 2 +- .../Converters/DividendSeriesConverter.ts | 2 +- .../Converters/GrowthSeriesConverter.ts | 2 +- .../Converters/RatingSeriesConverter.ts | 2 +- .../TimeSeries/DividendConverter.test.ts | 6 +++++ test/unit-tests/runtime.ts | 26 +++++++++---------- 6 files changed, 23 insertions(+), 17 deletions(-) diff --git a/src/TimeSeries/Converters/CumulativeReturnSeriesConverter.ts b/src/TimeSeries/Converters/CumulativeReturnSeriesConverter.ts index 0663d9e..7c6972a 100644 --- a/src/TimeSeries/Converters/CumulativeReturnSeriesConverter.ts +++ b/src/TimeSeries/Converters/CumulativeReturnSeriesConverter.ts @@ -145,7 +145,7 @@ export class CumulativeReturnSeriesConverter extends MorningstarConverter { // Add returns to table let currentTableDate: number = 0; - let currentTableIndex: number = 0; + let currentTableIndex: number = -1; for (const return_ of sortedReturns) { if (currentTableDate !== return_.EndDate) { diff --git a/src/TimeSeries/Converters/DividendSeriesConverter.ts b/src/TimeSeries/Converters/DividendSeriesConverter.ts index 0d59063..8428228 100644 --- a/src/TimeSeries/Converters/DividendSeriesConverter.ts +++ b/src/TimeSeries/Converters/DividendSeriesConverter.ts @@ -152,7 +152,7 @@ export class DividendSeriesConverter extends MorningstarConverter { // Add dividends to table let currentTableDate: number = 0; - let currentTableIndex: number = 0; + let currentTableIndex: number = -1; for (const dividend of sortedDividends) { if (currentTableDate !== dividend.EndDate) { diff --git a/src/TimeSeries/Converters/GrowthSeriesConverter.ts b/src/TimeSeries/Converters/GrowthSeriesConverter.ts index 9a56ac6..d1814f7 100644 --- a/src/TimeSeries/Converters/GrowthSeriesConverter.ts +++ b/src/TimeSeries/Converters/GrowthSeriesConverter.ts @@ -145,7 +145,7 @@ export class GrowthSeriesConverter extends MorningstarConverter { // Add growths to table let currentTableDate: number = 0; - let currentTableIndex: number = 0; + let currentTableIndex: number = -1; for (const growth of sortedGrowths) { if (currentTableDate !== growth.EndDate) { diff --git a/src/TimeSeries/Converters/RatingSeriesConverter.ts b/src/TimeSeries/Converters/RatingSeriesConverter.ts index 3720b97..a2a8faf 100644 --- a/src/TimeSeries/Converters/RatingSeriesConverter.ts +++ b/src/TimeSeries/Converters/RatingSeriesConverter.ts @@ -145,7 +145,7 @@ export class RatingSeriesConverter extends MorningstarConverter { // Add ratings to table let currentTableDate: number = 0; - let currentTableIndex: number = 0; + let currentTableIndex: number = -1; for (const rating of sortedRatings) { if (currentTableDate !== rating.EndDate) { diff --git a/test/unit-tests/TimeSeries/DividendConverter.test.ts b/test/unit-tests/TimeSeries/DividendConverter.test.ts index 2bcc3c7..7acdd05 100644 --- a/test/unit-tests/TimeSeries/DividendConverter.test.ts +++ b/test/unit-tests/TimeSeries/DividendConverter.test.ts @@ -37,4 +37,10 @@ export async function rating_load( 'Connector table should exist of expected columns.' ); + Assert.strictEqual( + connector.table.getRowCount(), + 1, + 'Connector table should have one expected dividend row.' + ); + } diff --git a/test/unit-tests/runtime.ts b/test/unit-tests/runtime.ts index 62f5d58..08bb78e 100644 --- a/test/unit-tests/runtime.ts +++ b/test/unit-tests/runtime.ts @@ -170,18 +170,18 @@ async function runUnitTests() { const total = successes.length + failures.length; - if (successes.length === total) { + if (total && total === successes.length) { stdWrite( '✅', (total === 1 ? 'This' : 'All'), total, (total === 1 ? 'test' : 'tests'), - 'succeeded.\n' + 'succeeded. 🎉\n' ); } else { stdWrite( - '✅', successes.length, 'of', total, + '⭕️', successes.length, 'of', total, (total === 1 ? 'test' : 'tests'), 'succeeded.\n' ); @@ -194,8 +194,6 @@ async function runUnitTests() { } - process.exit(0); - } @@ -204,7 +202,7 @@ function stdWrite( ): void { process.stdout.write([ '[', - new Date().toISOString().substring(0, 19).replace('T', ' '), + new Date().toISOString().substring(11, 19), '] ', text.join(' ') ].join('')); @@ -221,10 +219,12 @@ function stdWrite( prepareGlobals(); -runUnitTests().catch(async error => { - - await logError(error); - - process.exit(1); - -}); +runUnitTests() + .then(() => { + console.log(); + process.exit(0); + }) + .catch(async error => { + await logError(error); + process.exit(1); + });