From fae1fee196483622011517dbcdfe4b43672d0b73 Mon Sep 17 00:00:00 2001 From: acheronfail Date: Wed, 23 Oct 2024 10:40:22 +1030 Subject: [PATCH 1/2] wip --- src/lib/misc.ts | 21 +++++ src/lib/parse/float-control.ts | 41 +++------ src/lib/parse/float-control.types.ts | 2 +- src/lib/parse/index.ts | 42 +++++---- src/lib/parse/types.ts | 2 + src/lib/parse/vesc.ts | 117 +++++++++++++++++++++++++ src/lib/parse/vesc.types.ts | 124 +++++++++++++++++++++++++++ 7 files changed, 299 insertions(+), 50 deletions(-) create mode 100644 src/lib/parse/vesc.ts create mode 100644 src/lib/parse/vesc.types.ts diff --git a/src/lib/misc.ts b/src/lib/misc.ts index 74f69af..f8ddef0 100644 --- a/src/lib/misc.ts +++ b/src/lib/misc.ts @@ -26,3 +26,24 @@ export const formatFloat = (n: number | undefined, allowInt = false) => { if (allowInt && Number.isInteger(n)) return n.toString(); return n.toFixed(1); }; + +const loggedHeaders = new Set(); +export const createHeaderTransformer = (mapper: Record) => (header: string) => { + const key = mapper[header]; + if (key === undefined && !loggedHeaders.has(header)) { + console.warn('Unknown header found in CSV file', { header }); + loggedHeaders.add(header); + } + + return key ?? header; +}; + +export const parseFloatValue = (input: string): number => { + const float = parseFloat(input); + if (Number.isNaN(float)) { + console.warn(`Failed to parse CSV! Expected a number, but got: '${input}'`); + return 0; + } + + return float; +}; \ No newline at end of file diff --git a/src/lib/parse/float-control.ts b/src/lib/parse/float-control.ts index b3de9b8..68b4c7d 100644 --- a/src/lib/parse/float-control.ts +++ b/src/lib/parse/float-control.ts @@ -1,24 +1,11 @@ -import csv, { type ParseResult } from 'papaparse'; -import { floatControlKeyMap, FloatControlRawHeader } from './float-control.types'; +import csv from 'papaparse'; +import { floatControlToRowMap, FloatControlRawHeader } from './float-control.types'; import demoCsv from '../../assets/demo.csv?raw'; -import { attachIndex } from '../misc'; -import { RowKey, State, type Row, type RowWithIndex, Units } from './types'; +import { attachIndex, createHeaderTransformer, parseFloatValue } from '../misc'; +import { RowKey, State, type Row, type RowWithIndex, Units, DataSource } from './types'; +import { ParseError, type ParseResult } from './index'; -const transformHeader = (header: string) => { - const key = floatControlKeyMap[header as FloatControlRawHeader]; - if (!key) console.warn('Unknown header found in CSV file', { header }); - return key ?? header; -}; - -const parseFloatValue = (input: string): number => { - const float = parseFloat(input); - if (Number.isNaN(float)) { - console.warn(`Failed to parse CSV! Expected a number, but got: '${input}'`); - return 0; - } - - return float; -}; +const transformHeader = createHeaderTransformer(floatControlToRowMap); const transform = (value: string, column: C): Row[C] => { switch (column) { @@ -56,12 +43,7 @@ const parseOptions = { transform, }; -export interface FloatControlData { - csv: ParseResult; - units: Units; -} - -export function parseFloatControlCsv(input: string | File): Promise { +export function parseFloatControlCsv(input: string | File): Promise { let units = Units.Imperial; return new Promise((resolve) => { csv.parse(input, { @@ -74,10 +56,15 @@ export function parseFloatControlCsv(input: string | File): Promise { - results.data = attachIndex(results.data); + const data = attachIndex(results.data); resolve({ - csv: results as ParseResult, + source: DataSource.FloatControl, + data, units, + error: + results.errors.length > 0 + ? new ParseError('Failed to parse Float Control CSV!', results.errors) + : undefined, }); }, }); diff --git a/src/lib/parse/float-control.types.ts b/src/lib/parse/float-control.types.ts index 853e25a..b55d11e 100644 --- a/src/lib/parse/float-control.types.ts +++ b/src/lib/parse/float-control.types.ts @@ -44,7 +44,7 @@ export enum FloatControlRawHeader { WhCharged = 'Wh Charged', } -export const floatControlKeyMap: Record = { +export const floatControlToRowMap: Record = { [FloatControlRawHeader.Adc1]: RowKey.Adc1, [FloatControlRawHeader.Adc2]: RowKey.Adc2, [FloatControlRawHeader.Ah]: RowKey.Ah, diff --git a/src/lib/parse/index.ts b/src/lib/parse/index.ts index 406fa93..413e1b9 100644 --- a/src/lib/parse/index.ts +++ b/src/lib/parse/index.ts @@ -3,6 +3,7 @@ import * as fflate from 'fflate'; import { parseFloatControlCsv } from './float-control'; import { parseFloatyJson } from './floaty'; import { DataSource, Units, type RowWithIndex } from './types'; +import { parseVescToolCsv } from './vesc'; export class ParseError extends Error { constructor( @@ -21,9 +22,9 @@ export interface ParseResult { } export enum SupportedMimeTypes { - /** Float Control's CSV */ + /** VESC Tool or Float Control CSV */ Csv = 'text/csv', - /** Float Control's Zipped CSV */ + /** VESC Tool or Float Control Zipped CSV */ Zip1 = 'application/zip', Zip2 = 'application/x-zip-compressed', /** Floaty's JSON */ @@ -33,6 +34,21 @@ export enum SupportedMimeTypes { export const supportedMimeTypes = Object.values(SupportedMimeTypes); export const supportedMimeTypeString = supportedMimeTypes.join(','); +async function parseCsv(input: string | File): Promise { + if (typeof input !== 'string') { + const first100Bytes = await input.slice(0, 100).text(); + const semiColonCount = first100Bytes.split(';').length - 1; + + // VESC Tool delimits by semi-colon, so we use that to detect if it's CSV + // generated by VESC Tool or Float Control + if (semiColonCount > 1) { + return parseVescToolCsv(input); + } + } + + return await parseFloatControlCsv(input); +} + export async function parse(file: File): Promise { const lowerName = file.name.toLowerCase(); if (file.type === SupportedMimeTypes.Zip1 || file.type === SupportedMimeTypes.Zip2 || lowerName.endsWith('.zip')) { @@ -48,29 +64,11 @@ export async function parse(file: File): Promise { } const unzippedBytes = fileMap[fileList[0]!]!; - const parsed = await parseFloatControlCsv(new TextDecoder().decode(unzippedBytes)); - return { - source: DataSource.FloatControl, - data: parsed.csv.data, - units: parsed.units, - error: - parsed.csv.errors.length > 0 - ? new ParseError('Failed to parse Float Control CSV properly!', parsed.csv.errors) - : undefined, - }; + return await parseCsv(new TextDecoder().decode(unzippedBytes)); } if (file.type === SupportedMimeTypes.Csv || lowerName.endsWith('.csv')) { - const parsed = await parseFloatControlCsv(file); - return { - source: DataSource.FloatControl, - data: parsed.csv.data, - units: parsed.units, - error: - parsed.csv.errors.length > 0 - ? new ParseError('Failed to parse Float Control CSV properly!', parsed.csv.errors) - : undefined, - }; + return await parseCsv(file); } if (file.type === SupportedMimeTypes.Json || lowerName.endsWith('.json')) { diff --git a/src/lib/parse/types.ts b/src/lib/parse/types.ts index c28d2a0..814189d 100644 --- a/src/lib/parse/types.ts +++ b/src/lib/parse/types.ts @@ -2,6 +2,7 @@ export enum DataSource { None = 'none', FloatControl = 'float_control', Floaty = 'floaty', + VescTool = 'vesc_tool', } export enum Units { @@ -63,6 +64,7 @@ export const empty: RowWithIndex = { wh: 0, }; +// TODO: make keyof export enum RowKey { Adc1 = 'adc1', Adc2 = 'adc2', diff --git a/src/lib/parse/vesc.ts b/src/lib/parse/vesc.ts new file mode 100644 index 0000000..17f788b --- /dev/null +++ b/src/lib/parse/vesc.ts @@ -0,0 +1,117 @@ +import csv from 'papaparse'; +import { ParseError, type ParseResult } from './index'; +import { DataSource, RowKey, Units, type Row, type RowWithIndex } from './types'; +import { createHeaderTransformer, parseFloatValue } from '../misc'; +import { vescToolToRowMap, type RequiredRowValues } from './vesc.types'; + +// { +// "time": "60848530", +// "voltage": "81.5", +// "temp_mosfet": "18.8", +// "temp_mos_1": "18.9", +// "temp_mos_2": "0", +// "temp_mos_3": "18.6", +// "temp_motor": "26.5", +// "current_motor": "0", +// "current_battery": "0", +// "d_axis_current": "0", +// "q_axis_current": "0", +// "erpm": "0", +// "duty": "0.001", +// "ah": "0.6502", +// "ah_charged": "0.0577", +// "wh": "51.836", +// "wh_charged": "4.7486", +// "tachometer": "195978", +// "tachometer_abs": "196754", +// "encoder_position": "180", +// "motor_fault": "0", +// "vesc_id": "102", +// "d_axis_voltage": "-0.09", +// "q_axis_voltage": "0.001", +// "ms_today_setup": "60848444", +// "amp_hours_setup": "0.6502", +// "amp_hours_charged_setup": "0.0577", +// "watt_hours_setup": "51.836", +// "watt_hours_charged_setup": "4.7486", +// "battery_level": "0.889", +// "battery_wh_tot": "313.214", +// "current_in_setup": "0", +// "current_motor_setup": "0", +// "speed": "0", +// "tacho_meters": "1710.23", +// "tacho_abs_meters": "1717", +// "num_vescs": "1", +// "ms_today_imu": "60800384", +// "roll": "0", +// "pitch": "0.295746", +// "yaw": "0", +// "accX": "0", +// "accY": "0", +// "accZ": "0", +// "gyroX": "0", +// "gyroY": "0", +// "gyroZ": "0", +// "gnss_posTime": "-1", +// "gps_latitude": "0.00000000", +// "gps_longitude": "0.00000000", +// "altitude": "0.00000000", +// "gnss_gVel": "0.00000000", +// "gnss_vVel": "0.00000000", +// "gps_accuracy": "0.00000000", +// "gnss_vAcc": "0.00000000", +// "": "", +// "index": 0 +// } + +const transform = (value: string, column: C): Row[C] => { + switch (column) { + // @ts-ignore FIXME + case '': + return '' as Row[C]; + case RowKey.Duty: + return parseFloatValue(value) * 100 as Row[C]; + default: + return parseFloatValue(value) as Row[C]; + } +}; + +// TODO: convert speed from m/s to km/h +// TODO: parse floats are needed +// TODO: any other mappings as required +export async function parseVescToolCsv(input: string | File): Promise { + return new Promise((resolve) => { + csv.parse>(input, { + header: true, + delimiter: ';', + skipEmptyLines: true, + fastMode: true, + transformHeader: createHeaderTransformer(vescToolToRowMap), + transform, + complete: (results) => { + console.log('csv parse', results.data.length); + for (let i = 0; i < results.data.length; ++i) { + const out = results.data[i] as RowWithIndex; + out.index = i; + // RowKey.Adc1 | RowKey.Adc2 | RowKey.Distance | RowKey.State | RowKey.StateRaw | RowKey.TruePitch + out.adc1 = 0; + out.adc2 = 0; + out.distance = 0; + out.state = 'UNKNOWN'; + out.state_raw = 0; + out.true_pitch = out.pitch; + } + + console.log('csv patch'); + + resolve({ + source: DataSource.VescTool, + data: results.data as RowWithIndex[], + units: Units.Metric, + error: + results.errors.length > 0 ? new ParseError('Failed to parse VESC Tool CSV!', results.errors) : undefined, + }); + }, + }); + }); +} diff --git a/src/lib/parse/vesc.types.ts b/src/lib/parse/vesc.types.ts new file mode 100644 index 0000000..7ff6b05 --- /dev/null +++ b/src/lib/parse/vesc.types.ts @@ -0,0 +1,124 @@ +import { RowKey, type Row } from './types'; + +export enum VescToolHeader { + AccX = 'accX', + AccY = 'accY', + AccZ = 'accZ', + AmpHoursCharged = 'amp_hours_charged', + AmpHoursChargedSetup = 'amp_hours_charged_setup', + AmpHoursSetup = 'amp_hours_setup', + AmpHoursUsed = 'amp_hours_used', + BatteryLevel = 'battery_level', + BatteryWhTot = 'battery_wh_tot', + CurrentIn = 'current_in', + CurrentInSetup = 'current_in_setup', + CurrentMotor = 'current_motor', + CurrentMotorSetup = 'current_motor_setup', + DAxisCurrent = 'd_axis_current', + DAxisVoltage = 'd_axis_voltage', + DutyCycle = 'duty_cycle', + EncoderPosition = 'encoder_position', + Erpm = 'erpm', + FaultCode = 'fault_code', + GnssAlt = 'gnss_alt', + GnssGVel = 'gnss_gVel', + GnssHAcc = 'gnss_hAcc', + GnssLat = 'gnss_lat', + GnssLon = 'gnss_lon', + GnssPosTime = 'gnss_posTime', + GnssVAcc = 'gnss_vAcc', + GnssVVel = 'gnss_vVel', + GyroX = 'gyroX', + GyroY = 'gyroY', + GyroZ = 'gyroZ', + InputVoltage = 'input_voltage', + MsToday = 'ms_today', + MsTodayImu = 'ms_today_imu', + MsTodaySetup = 'ms_today_setup', + NumVescs = 'num_vescs', + Pitch = 'pitch', + QAxisCurrent = 'q_axis_current', + QAxisVoltage = 'q_axis_voltage', + Roll = 'roll', + SpeedMetersPerSec = 'speed_meters_per_sec', + TachoAbsMeters = 'tacho_abs_meters', + Tachometer = 'tachometer', + TachometerAbs = 'tachometer_abs', + TachoMeters = 'tacho_meters', + TempMos_1 = 'temp_mos_1', + TempMos_2 = 'temp_mos_2', + TempMos_3 = 'temp_mos_3', + TempMosMax = 'temp_mos_max', + TempMotor = 'temp_motor', + VescId = 'vesc_id', + WattHoursCharged = 'watt_hours_charged', + WattHoursChargedSetup = 'watt_hours_charged_setup', + WattHoursSetup = 'watt_hours_setup', + WattHoursUsed = 'watt_hours_used', + Yaw = 'yaw', +} + +type VescValues = (typeof vescToolToRowMap)[VescToolHeader]; +export type RequiredRowValues = NonNullable< + { + [k in keyof Row]: undefined extends Row[k] ? never : k extends VescValues ? never : k; + }[keyof Row] +>; + +export const vescToolToRowMap = { + [VescToolHeader.AccX]: undefined, + [VescToolHeader.AccY]: undefined, + [VescToolHeader.AccZ]: undefined, + [VescToolHeader.AmpHoursCharged]: RowKey.AhCharged, + [VescToolHeader.AmpHoursChargedSetup]: undefined, + [VescToolHeader.AmpHoursSetup]: undefined, + [VescToolHeader.AmpHoursUsed]: RowKey.Ah, + [VescToolHeader.BatteryLevel]: undefined, + [VescToolHeader.BatteryWhTot]: undefined, + [VescToolHeader.CurrentIn]: RowKey.CurrentBattery, + [VescToolHeader.CurrentInSetup]: undefined, + [VescToolHeader.CurrentMotor]: RowKey.CurrentMotor, + [VescToolHeader.CurrentMotorSetup]: undefined, + [VescToolHeader.DAxisCurrent]: undefined, + [VescToolHeader.DAxisVoltage]: undefined, + [VescToolHeader.DutyCycle]: RowKey.Duty, + [VescToolHeader.EncoderPosition]: undefined, + [VescToolHeader.Erpm]: RowKey.Erpm, + [VescToolHeader.FaultCode]: RowKey.MotorFault, + [VescToolHeader.GnssAlt]: RowKey.Altitude, + [VescToolHeader.GnssGVel]: undefined, + [VescToolHeader.GnssHAcc]: RowKey.GpsAccuracy, + [VescToolHeader.GnssLat]: RowKey.GpsLatitude, + [VescToolHeader.GnssLon]: RowKey.GpsLongitude, + [VescToolHeader.GnssPosTime]: undefined, + [VescToolHeader.GnssVAcc]: undefined, + [VescToolHeader.GnssVVel]: undefined, + [VescToolHeader.GyroX]: undefined, + [VescToolHeader.GyroY]: undefined, + [VescToolHeader.GyroZ]: undefined, + [VescToolHeader.InputVoltage]: RowKey.Voltage, + [VescToolHeader.MsToday]: RowKey.Time, + [VescToolHeader.MsTodayImu]: undefined, + [VescToolHeader.MsTodaySetup]: undefined, + [VescToolHeader.NumVescs]: undefined, + [VescToolHeader.Pitch]: RowKey.Pitch, + [VescToolHeader.QAxisCurrent]: undefined, + [VescToolHeader.QAxisVoltage]: undefined, + [VescToolHeader.Roll]: RowKey.Roll, + [VescToolHeader.SpeedMetersPerSec]: RowKey.Speed, + [VescToolHeader.TachoAbsMeters]: undefined, + [VescToolHeader.Tachometer]: undefined, + [VescToolHeader.TachometerAbs]: undefined, + [VescToolHeader.TachoMeters]: undefined, + [VescToolHeader.TempMos_1]: undefined, + [VescToolHeader.TempMos_2]: undefined, + [VescToolHeader.TempMos_3]: undefined, + [VescToolHeader.TempMosMax]: RowKey.TempMosfet, + [VescToolHeader.TempMotor]: RowKey.TempMotor, + [VescToolHeader.VescId]: undefined, + [VescToolHeader.WattHoursCharged]: RowKey.WhCharged, + [VescToolHeader.WattHoursChargedSetup]: undefined, + [VescToolHeader.WattHoursSetup]: undefined, + [VescToolHeader.WattHoursUsed]: RowKey.Wh, + [VescToolHeader.Yaw]: undefined, +} satisfies Record; From fae1e8441dbc3b154925a13a6ca41c3896fe8397 Mon Sep 17 00:00:00 2001 From: acheronfail Date: Mon, 28 Oct 2024 12:47:46 +1030 Subject: [PATCH 2/2] patch: add blob-polyfill and update svelte from beta --- package-lock.json | 384 ++++++++-------------------- package.json | 9 +- src/components/Map.svelte | 24 +- src/lib/misc.ts | 2 +- src/lib/parse/float-control.test.ts | 36 +-- src/lib/parse/vesc.ts | 2 +- src/setup-tests.ts | 1 + 7 files changed, 139 insertions(+), 319 deletions(-) diff --git a/package-lock.json b/package-lock.json index 29e8179..703218e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,22 +15,23 @@ "zod": "^3.23.8" }, "devDependencies": { - "@sveltejs/vite-plugin-svelte": "^4.0.0-next.7", + "@sveltejs/vite-plugin-svelte": "^4.0.0", "@testing-library/jest-dom": "^6.5.0", - "@testing-library/svelte": "^5.2.1", + "@testing-library/svelte": "^5.2.4", "@tsconfig/svelte": "^5.0.4", "@types/leaflet": "^1.9.12", "@types/papaparse": "^5.3.14", "@types/semver": "^7.5.8", "autoprefixer": "^10.4.20", + "blob-polyfill": "^9.0.20240710", "concurrently": "^9.0.1", "jsdom": "^25.0.0", "postcss": "^8.4.45", "prettier": "^3.3.3", "prettier-plugin-svelte": "^3.2.6", "semver": "^7.6.3", - "svelte": "^5.0.0-next.243", - "svelte-check": "^3.8.6", + "svelte": "^5.1.3", + "svelte-check": "^4.0.5", "tailwindcss": "^3.4.11", "tslib": "^2.6.3", "tsx": "^4.19.1", @@ -902,17 +903,17 @@ ] }, "node_modules/@sveltejs/vite-plugin-svelte": { - "version": "4.0.0-next.7", - "resolved": "https://packages.atlassian.com/api/npm/npm-remote/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-4.0.0-next.7.tgz", - "integrity": "sha512-yMUnAqquoayvBDztk1rWUgdtvjv7YcHgopCAB7sWl9SQht8U/7lqwTlJU0ZTAY09pFFRe6bbakd7YoiyyIvJiA==", + "version": "4.0.0", + "resolved": "https://packages.atlassian.com/api/npm/npm-remote/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-4.0.0.tgz", + "integrity": "sha512-kpVJwF+gNiMEsoHaw+FJL76IYiwBikkxYU83+BpqQLdVMff19KeRKLd2wisS8niNBMJ2omv5gG+iGDDwd8jzag==", "dev": true, "dependencies": { "@sveltejs/vite-plugin-svelte-inspector": "^3.0.0-next.0||^3.0.0", - "debug": "^4.3.6", + "debug": "^4.3.7", "deepmerge": "^4.3.1", "kleur": "^4.1.5", - "magic-string": "^0.30.11", - "vitefu": "^1.0.2" + "magic-string": "^0.30.12", + "vitefu": "^1.0.3" }, "engines": { "node": "^18.0.0 || ^20.0.0 || >=22" @@ -998,9 +999,9 @@ "dev": true }, "node_modules/@testing-library/svelte": { - "version": "5.2.1", - "resolved": "https://packages.atlassian.com/api/npm/npm-remote/@testing-library/svelte/-/svelte-5.2.1.tgz", - "integrity": "sha512-yXSqBsYaQAeP2xt7gqKu135Q67+NTsBDcpL1akv5MVAQ/amb7AQ0zW5nzrquTIE2lvrc6q58KZhQA61Vc05ZOg==", + "version": "5.2.4", + "resolved": "https://packages.atlassian.com/api/npm/npm-remote/@testing-library/svelte/-/svelte-5.2.4.tgz", + "integrity": "sha512-EFdy73+lULQgMJ1WolAymrxWWrPv9DWyDuDFKKlUip2PA/EXuHptzfYOKWljccFWDKhhGOu3dqNmoc2f/h/Ecg==", "dev": true, "dependencies": { "@testing-library/dom": "^10.0.0" @@ -1073,12 +1074,6 @@ "@types/node": "*" } }, - "node_modules/@types/pug": { - "version": "2.0.10", - "resolved": "https://packages.atlassian.com/api/npm/npm-remote/@types/pug/-/pug-2.0.10.tgz", - "integrity": "sha512-Sk/uYFOBAB7mb74XcpizmH0KOR2Pv3D2Hmrh1Dmy5BmK3MpdSa5kqZcg6EKBdklU0bFXX9gCfzvpnyUehrPIuA==", - "dev": true - }, "node_modules/@types/semver": { "version": "7.5.8", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", @@ -1363,15 +1358,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://packages.atlassian.com/api/npm/npm-remote/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } + "node_modules/blob-polyfill": { + "version": "9.0.20240710", + "resolved": "https://packages.atlassian.com/api/npm/npm-remote/blob-polyfill/-/blob-polyfill-9.0.20240710.tgz", + "integrity": "sha512-DPUO/EjNANCgSVg0geTy1vmUpu5hhp9tV2F7xUSTUd1jwe4XpwupGB+lt5PhVUqpqAk+zK1etqp6Pl/HVf71Ug==", + "dev": true }, "node_modules/braces": { "version": "3.0.3", @@ -1417,15 +1408,6 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, - "node_modules/buffer-crc32": { - "version": "1.0.0", - "resolved": "https://packages.atlassian.com/api/npm/npm-remote/buffer-crc32/-/buffer-crc32-1.0.0.tgz", - "integrity": "sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==", - "dev": true, - "engines": { - "node": ">=8.0.0" - } - }, "node_modules/cac": { "version": "6.7.14", "resolved": "https://packages.atlassian.com/api/npm/npm-remote/cac/-/cac-6.7.14.tgz", @@ -1636,12 +1618,6 @@ "node": ">= 6" } }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://packages.atlassian.com/api/npm/npm-remote/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, "node_modules/concurrently": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-9.0.1.tgz", @@ -1748,12 +1724,12 @@ } }, "node_modules/debug": { - "version": "4.3.6", - "resolved": "https://packages.atlassian.com/api/npm/npm-remote/debug/-/debug-4.3.6.tgz", - "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", + "version": "4.3.7", + "resolved": "https://packages.atlassian.com/api/npm/npm-remote/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", "dev": true, "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -1806,15 +1782,6 @@ "node": ">=6" } }, - "node_modules/detect-indent": { - "version": "6.1.0", - "resolved": "https://packages.atlassian.com/api/npm/npm-remote/detect-indent/-/detect-indent-6.1.0.tgz", - "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/didyoumean": { "version": "1.2.2", "resolved": "https://packages.atlassian.com/api/npm/npm-remote/didyoumean/-/didyoumean-1.2.2.tgz", @@ -1863,12 +1830,6 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, - "node_modules/es6-promise": { - "version": "3.3.1", - "resolved": "https://packages.atlassian.com/api/npm/npm-remote/es6-promise/-/es6-promise-3.3.1.tgz", - "integrity": "sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==", - "dev": true - }, "node_modules/esbuild": { "version": "0.21.5", "resolved": "https://packages.atlassian.com/api/npm/npm-remote/esbuild/-/esbuild-0.21.5.tgz", @@ -2035,12 +1996,6 @@ "url": "https://github.com/sponsors/rawify" } }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://packages.atlassian.com/api/npm/npm-remote/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://packages.atlassian.com/api/npm/npm-remote/fsevents/-/fsevents-2.3.3.tgz", @@ -2096,27 +2051,6 @@ "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" } }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://packages.atlassian.com/api/npm/npm-remote/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/glob-parent": { "version": "5.1.2", "resolved": "https://packages.atlassian.com/api/npm/npm-remote/glob-parent/-/glob-parent-5.1.2.tgz", @@ -2129,12 +2063,6 @@ "node": ">= 6" } }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://packages.atlassian.com/api/npm/npm-remote/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true - }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://packages.atlassian.com/api/npm/npm-remote/has-flag/-/has-flag-4.0.0.tgz", @@ -2215,23 +2143,6 @@ "node": ">=8" } }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://packages.atlassian.com/api/npm/npm-remote/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://packages.atlassian.com/api/npm/npm-remote/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, "node_modules/is-binary-path": { "version": "2.1.0", "resolved": "https://packages.atlassian.com/api/npm/npm-remote/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -2465,9 +2376,9 @@ } }, "node_modules/magic-string": { - "version": "0.30.11", - "resolved": "https://packages.atlassian.com/api/npm/npm-remote/magic-string/-/magic-string-0.30.11.tgz", - "integrity": "sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==", + "version": "0.30.12", + "resolved": "https://packages.atlassian.com/api/npm/npm-remote/magic-string/-/magic-string-0.30.12.tgz", + "integrity": "sha512-Ea8I3sQMVXr8JhN4z+H/d8zwo+tYDgHE9+5G4Wnrwhs0gaK9fXTKx0Tw5Xwsd/bCPTTZNRAdpyzvoeORe9LYpw==", "dev": true, "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0" @@ -2525,27 +2436,6 @@ "node": ">=4" } }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://packages.atlassian.com/api/npm/npm-remote/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://packages.atlassian.com/api/npm/npm-remote/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/minipass": { "version": "7.1.2", "resolved": "https://packages.atlassian.com/api/npm/npm-remote/minipass/-/minipass-7.1.2.tgz", @@ -2555,18 +2445,6 @@ "node": ">=16 || 14 >=14.17" } }, - "node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://packages.atlassian.com/api/npm/npm-remote/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "dev": true, - "dependencies": { - "minimist": "^1.2.6" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, "node_modules/moo-color": { "version": "1.0.3", "resolved": "https://packages.atlassian.com/api/npm/npm-remote/moo-color/-/moo-color-1.0.3.tgz", @@ -2586,9 +2464,9 @@ } }, "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://packages.atlassian.com/api/npm/npm-remote/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "version": "2.1.3", + "resolved": "https://packages.atlassian.com/api/npm/npm-remote/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, "node_modules/mz": { @@ -2668,15 +2546,6 @@ "node": ">= 6" } }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://packages.atlassian.com/api/npm/npm-remote/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, "node_modules/package-json-from-dist": { "version": "1.0.0", "resolved": "https://packages.atlassian.com/api/npm/npm-remote/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", @@ -2700,15 +2569,6 @@ "url": "https://github.com/inikulin/parse5?sponsor=1" } }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://packages.atlassian.com/api/npm/npm-remote/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://packages.atlassian.com/api/npm/npm-remote/path-key/-/path-key-3.1.1.tgz", @@ -3137,19 +2997,6 @@ "node": ">=0.10.0" } }, - "node_modules/rimraf": { - "version": "2.7.1", - "resolved": "https://packages.atlassian.com/api/npm/npm-remote/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, "node_modules/rollup": { "version": "4.22.4", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.22.4.tgz", @@ -3243,18 +3090,6 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true }, - "node_modules/sander": { - "version": "0.5.1", - "resolved": "https://packages.atlassian.com/api/npm/npm-remote/sander/-/sander-0.5.1.tgz", - "integrity": "sha512-3lVqBir7WuKDHGrKRDn/1Ye3kwpXaDOMsiRP1wd6wpZW56gJhsbp5RqQpA6JG/P+pkXizygnr1dKR8vzWaVsfA==", - "dev": true, - "dependencies": { - "es6-promise": "^3.1.2", - "graceful-fs": "^4.1.3", - "mkdirp": "^0.5.1", - "rimraf": "^2.5.2" - } - }, "node_modules/saxes": { "version": "6.0.0", "resolved": "https://packages.atlassian.com/api/npm/npm-remote/saxes/-/saxes-6.0.0.tgz", @@ -3329,21 +3164,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/sorcery": { - "version": "0.11.1", - "resolved": "https://packages.atlassian.com/api/npm/npm-remote/sorcery/-/sorcery-0.11.1.tgz", - "integrity": "sha512-o7npfeJE6wi6J9l0/5LKshFzZ2rMatRiCDwYeDQaOzqdzRJwALhX7mk/A/ecg6wjMu7wdZbmXfD2S/vpOg0bdQ==", - "dev": true, - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.14", - "buffer-crc32": "^1.0.0", - "minimist": "^1.2.0", - "sander": "^0.5.0" - }, - "bin": { - "sorcery": "bin/sorcery" - } - }, "node_modules/source-map-js": { "version": "1.2.0", "resolved": "https://packages.atlassian.com/api/npm/npm-remote/source-map-js/-/source-map-js-1.2.0.tgz", @@ -3558,9 +3378,9 @@ } }, "node_modules/svelte": { - "version": "5.0.0-next.243", - "resolved": "https://packages.atlassian.com/api/npm/npm-remote/svelte/-/svelte-5.0.0-next.243.tgz", - "integrity": "sha512-+oXjRInUyBfZXAEY8hmpf3F0eghAVCoWasotz1iOp2G5CyH4KR7jPxWOgjbgsgpL4zlMiN32MEYU1+I+QsC+nQ==", + "version": "5.1.3", + "resolved": "https://packages.atlassian.com/api/npm/npm-remote/svelte/-/svelte-5.1.3.tgz", + "integrity": "sha512-Sl8UFHlBvF54aK8MElFvyvaUfPE2REOz6LnhR2pBClCL11MU4qpn4V+KgAggaXxDyrP2iQixvHbtpHqL/zXlSQ==", "dev": true, "dependencies": { "@ampproject/remapping": "^2.3.0", @@ -3568,7 +3388,7 @@ "@types/estree": "^1.0.5", "acorn": "^8.12.1", "acorn-typescript": "^1.4.13", - "aria-query": "^5.3.0", + "aria-query": "^5.3.1", "axobject-query": "^4.1.0", "esm-env": "^1.0.0", "esrap": "^1.2.2", @@ -3582,87 +3402,93 @@ } }, "node_modules/svelte-check": { - "version": "3.8.6", - "resolved": "https://packages.atlassian.com/api/npm/npm-remote/svelte-check/-/svelte-check-3.8.6.tgz", - "integrity": "sha512-ij0u4Lw/sOTREP13BdWZjiXD/BlHE6/e2e34XzmVmsp5IN4kVa3PWP65NM32JAgwjZlwBg/+JtiNV1MM8khu0Q==", + "version": "4.0.5", + "resolved": "https://packages.atlassian.com/api/npm/npm-remote/svelte-check/-/svelte-check-4.0.5.tgz", + "integrity": "sha512-icBTBZ3ibBaywbXUat3cK6hB5Du+Kq9Z8CRuyLmm64XIe2/r+lQcbuBx/IQgsbrC+kT2jQ0weVpZSSRIPwB6jQ==", "dev": true, "dependencies": { - "@jridgewell/trace-mapping": "^0.3.17", - "chokidar": "^3.4.1", + "@jridgewell/trace-mapping": "^0.3.25", + "chokidar": "^4.0.1", + "fdir": "^6.2.0", "picocolors": "^1.0.0", - "sade": "^1.7.4", - "svelte-preprocess": "^5.1.3", - "typescript": "^5.0.3" + "sade": "^1.7.4" }, "bin": { "svelte-check": "bin/svelte-check" }, + "engines": { + "node": ">= 18.0.0" + }, "peerDependencies": { - "svelte": "^3.55.0 || ^4.0.0-next.0 || ^4.0.0 || ^5.0.0-next.0" + "svelte": "^4.0.0 || ^5.0.0-next.0", + "typescript": ">=5.0.0" } }, - "node_modules/svelte-preprocess": { - "version": "5.1.4", - "resolved": "https://packages.atlassian.com/api/npm/npm-remote/svelte-preprocess/-/svelte-preprocess-5.1.4.tgz", - "integrity": "sha512-IvnbQ6D6Ao3Gg6ftiM5tdbR6aAETwjhHV+UKGf5bHGYR69RQvF1ho0JKPcbUON4vy4R7zom13jPjgdOWCQ5hDA==", + "node_modules/svelte-check/node_modules/chokidar": { + "version": "4.0.1", + "resolved": "https://packages.atlassian.com/api/npm/npm-remote/chokidar/-/chokidar-4.0.1.tgz", + "integrity": "sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==", "dev": true, - "hasInstallScript": true, "dependencies": { - "@types/pug": "^2.0.6", - "detect-indent": "^6.1.0", - "magic-string": "^0.30.5", - "sorcery": "^0.11.0", - "strip-indent": "^3.0.0" + "readdirp": "^4.0.1" }, "engines": { - "node": ">= 16.0.0" + "node": ">= 14.16.0" }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/svelte-check/node_modules/fdir": { + "version": "6.4.2", + "resolved": "https://packages.atlassian.com/api/npm/npm-remote/fdir/-/fdir-6.4.2.tgz", + "integrity": "sha512-KnhMXsKSPZlAhp7+IjUkRZKPb4fUyccpDrdFXbi4QL1qkmFh9kVY09Yox+n4MaOb3lHZ1Tv829C3oaaXoMYPDQ==", + "dev": true, "peerDependencies": { - "@babel/core": "^7.10.2", - "coffeescript": "^2.5.1", - "less": "^3.11.3 || ^4.0.0", - "postcss": "^7 || ^8", - "postcss-load-config": "^2.1.0 || ^3.0.0 || ^4.0.0 || ^5.0.0", - "pug": "^3.0.0", - "sass": "^1.26.8", - "stylus": "^0.55.0", - "sugarss": "^2.0.0 || ^3.0.0 || ^4.0.0", - "svelte": "^3.23.0 || ^4.0.0-next.0 || ^4.0.0 || ^5.0.0-next.0", - "typescript": ">=3.9.5 || ^4.0.0 || ^5.0.0" + "picomatch": "^3 || ^4" }, "peerDependenciesMeta": { - "@babel/core": { - "optional": true - }, - "coffeescript": { - "optional": true - }, - "less": { - "optional": true - }, - "postcss": { - "optional": true - }, - "postcss-load-config": { - "optional": true - }, - "pug": { - "optional": true - }, - "sass": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "typescript": { + "picomatch": { "optional": true } } }, + "node_modules/svelte-check/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://packages.atlassian.com/api/npm/npm-remote/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "optional": true, + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/svelte-check/node_modules/readdirp": { + "version": "4.0.2", + "resolved": "https://packages.atlassian.com/api/npm/npm-remote/readdirp/-/readdirp-4.0.2.tgz", + "integrity": "sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==", + "dev": true, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/svelte/node_modules/aria-query": { + "version": "5.3.2", + "resolved": "https://packages.atlassian.com/api/npm/npm-remote/aria-query/-/aria-query-5.3.2.tgz", + "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/symbol-tree": { "version": "3.2.4", "resolved": "https://packages.atlassian.com/api/npm/npm-remote/symbol-tree/-/symbol-tree-3.2.4.tgz", @@ -4446,16 +4272,16 @@ } }, "node_modules/vitefu": { - "version": "1.0.2", - "resolved": "https://packages.atlassian.com/api/npm/npm-remote/vitefu/-/vitefu-1.0.2.tgz", - "integrity": "sha512-0/iAvbXyM3RiPPJ4lyD4w6Mjgtf4ejTK6TPvTNG3H32PLwuT0N/ZjJLiXug7ETE/LWtTeHw9WRv7uX/tIKYyKg==", + "version": "1.0.3", + "resolved": "https://packages.atlassian.com/api/npm/npm-remote/vitefu/-/vitefu-1.0.3.tgz", + "integrity": "sha512-iKKfOMBHob2WxEJbqbJjHAkmYgvFDPhuqrO82om83S8RLk+17FtyMBfcyeH8GqD0ihShtkMW/zzJgiA51hCNCQ==", "dev": true, "workspaces": [ "tests/deps/*", "tests/projects/*" ], "peerDependencies": { - "vite": "^3.0.0 || ^4.0.0 || ^5.0.0" + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0-beta.0" }, "peerDependenciesMeta": { "vite": { @@ -4704,12 +4530,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://packages.atlassian.com/api/npm/npm-remote/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true - }, "node_modules/ws": { "version": "8.18.0", "resolved": "https://packages.atlassian.com/api/npm/npm-remote/ws/-/ws-8.18.0.tgz", diff --git a/package.json b/package.json index 8d0950d..7186047 100644 --- a/package.json +++ b/package.json @@ -17,22 +17,23 @@ "ci:bump": "tsx scripts/bump.ts" }, "devDependencies": { - "@sveltejs/vite-plugin-svelte": "^4.0.0-next.7", + "@sveltejs/vite-plugin-svelte": "^4.0.0", "@testing-library/jest-dom": "^6.5.0", - "@testing-library/svelte": "^5.2.1", + "@testing-library/svelte": "^5.2.4", "@tsconfig/svelte": "^5.0.4", "@types/leaflet": "^1.9.12", "@types/papaparse": "^5.3.14", "@types/semver": "^7.5.8", "autoprefixer": "^10.4.20", + "blob-polyfill": "^9.0.20240710", "concurrently": "^9.0.1", "jsdom": "^25.0.0", "postcss": "^8.4.45", "prettier": "^3.3.3", "prettier-plugin-svelte": "^3.2.6", "semver": "^7.6.3", - "svelte": "^5.0.0-next.243", - "svelte-check": "^3.8.6", + "svelte": "^5.1.3", + "svelte-check": "^4.0.5", "tailwindcss": "^3.4.11", "tslib": "^2.6.3", "tsx": "^4.19.1", diff --git a/src/components/Map.svelte b/src/components/Map.svelte index f33d3b6..54d2053 100644 --- a/src/components/Map.svelte +++ b/src/components/Map.svelte @@ -53,11 +53,9 @@ $effect(() => { if (map) { - untrack(() => { - if (riderMarker) { - riderMarker.remove(); - } - }); + if (riderMarker) { + riderMarker.remove(); + } const latLng = gpsPoints[selectedRowIndex]; if (latLng) { @@ -81,20 +79,20 @@ }); $effect(() => { - untrack(() => { + // ensure this is updated each time the visible rows change + visibleRows; + + basePolyline = getBaseLine(gpsPoints, gpsGaps, hiddenRideSegments).addTo(map!); + travelledPolyline = getTravelledLine(gpsPoints, gpsGaps, selectedRowIndex, hiddenRideSegments).addTo(map!); + + return () => { if (basePolyline) { basePolyline.remove(); } if (travelledPolyline) { travelledPolyline.remove(); } - }); - - // ensure this is updated each time the visible rows change - visibleRows; - - basePolyline = getBaseLine(gpsPoints, gpsGaps, hiddenRideSegments).addTo(map!); - travelledPolyline = getTravelledLine(gpsPoints, gpsGaps, selectedRowIndex, hiddenRideSegments).addTo(map!); + }; }); function setVisibleIndices() { diff --git a/src/lib/misc.ts b/src/lib/misc.ts index f8ddef0..758eaa0 100644 --- a/src/lib/misc.ts +++ b/src/lib/misc.ts @@ -46,4 +46,4 @@ export const parseFloatValue = (input: string): number => { } return float; -}; \ No newline at end of file +}; diff --git a/src/lib/parse/float-control.test.ts b/src/lib/parse/float-control.test.ts index d79dd16..eefa1f6 100644 --- a/src/lib/parse/float-control.test.ts +++ b/src/lib/parse/float-control.test.ts @@ -13,48 +13,48 @@ describe(parseFloatControlCsv.name, () => { beforeEach(() => vi.restoreAllMocks()); test('metric', async () => { - const { units, csv } = await parseFloatControlCsv(csvMetric); + const { units, data, error } = await parseFloatControlCsv(csvMetric); expect(units).toBe('metric'); - expect(csv.errors).toEqual([]); - expect(csv.data).toEqual([defaultFixture]); + expect(error).toBeUndefined(); + expect(data).toEqual([defaultFixture]); }); test('metric with bms', async () => { - const { units, csv } = await parseFloatControlCsv(csvMetricWithBms); + const { units, data, error } = await parseFloatControlCsv(csvMetricWithBms); expect(units).toBe('metric'); - expect(csv.errors).toEqual([]); - expect(csv.data).toEqual([{ ...defaultFixture, ...defaultBms }]); + expect(error).toBeUndefined(); + expect(data).toEqual([{ ...defaultFixture, ...defaultBms }]); }); test('imperial', async () => { - const { units, csv } = await parseFloatControlCsv(csvImperial); + const { units, data, error } = await parseFloatControlCsv(csvImperial); expect(units).toBe('imperial'); - expect(csv.errors).toEqual([]); - expect(csv.data).toEqual([defaultFixture]); + expect(error).toBeUndefined(); + expect(data).toEqual([defaultFixture]); }); test('imperial with bms', async () => { - const { units, csv } = await parseFloatControlCsv(csvImperialWithBms); + const { units, data, error } = await parseFloatControlCsv(csvImperialWithBms); expect(units).toBe('imperial'); - expect(csv.errors).toEqual([]); - expect(csv.data).toEqual([{ ...defaultFixture, ...defaultBms }]); + expect(error).toBeUndefined(); + expect(data).toEqual([{ ...defaultFixture, ...defaultBms }]); }); test('with unknown state', async () => { const warnSpy = vi.spyOn(console, 'warn').mockReturnValue(); - const { units, csv } = await parseFloatControlCsv(csvWithUnknownState); + const { units, data, error } = await parseFloatControlCsv(csvWithUnknownState); expect(units).toBe('metric'); - expect(csv.errors).toEqual([]); - expect(csv.data).toEqual([{ ...defaultFixture, state: 'some_new_state' }]); + expect(error).toBeUndefined(); + expect(data).toEqual([{ ...defaultFixture, state: 'some_new_state' }]); expect(warnSpy).toHaveBeenCalledWith("Unknown state: 'SOME_NEW_STATE'"); }); test('with bad time', async () => { const warnSpy = vi.spyOn(console, 'warn').mockReturnValue(); - const { units, csv } = await parseFloatControlCsv(csvWithBadtime); + const { units, data, error } = await parseFloatControlCsv(csvWithBadtime); expect(units).toBe('metric'); - expect(csv.errors).toEqual([]); - expect(csv.data).toEqual([{ ...defaultFixture, time: 0 }]); + expect(error).toBeUndefined(); + expect(data).toEqual([{ ...defaultFixture, time: 0 }]); expect(warnSpy).toHaveBeenCalledWith("Failed to parse CSV! Expected a number, but got: 'I am not a number'"); }); }); diff --git a/src/lib/parse/vesc.ts b/src/lib/parse/vesc.ts index 17f788b..712fd17 100644 --- a/src/lib/parse/vesc.ts +++ b/src/lib/parse/vesc.ts @@ -70,7 +70,7 @@ const transform = (value: string, column: C): Row[C] => { case '': return '' as Row[C]; case RowKey.Duty: - return parseFloatValue(value) * 100 as Row[C]; + return (parseFloatValue(value) * 100) as Row[C]; default: return parseFloatValue(value) as Row[C]; } diff --git a/src/setup-tests.ts b/src/setup-tests.ts index 5062a6b..233ae90 100644 --- a/src/setup-tests.ts +++ b/src/setup-tests.ts @@ -1,2 +1,3 @@ import '@testing-library/jest-dom/vitest'; import 'vitest-canvas-mock'; +import 'blob-polyfill';