diff --git a/.betterer.results b/.betterer.results new file mode 100644 index 00000000..cc1be080 --- /dev/null +++ b/.betterer.results @@ -0,0 +1,971 @@ +// BETTERER RESULTS V2. +// +// If this file contains merge conflicts, use `betterer merge` to automatically resolve them: +// https://phenomnomnominal.github.io/betterer/docs/results-file/#merge +// +exports[`strictNullChecks`] = { + value: `{ + "src/app/app.component.ts:1462426010": [ + [112, 19, 25, "Object is possibly \'undefined\'.", "255143637"] + ], + "src/app/core/components/dashboard/dashboard.component.ts:1605211129": [ + [106, 12, 22, "Object is possibly \'undefined\'.", "2187394131"], + [116, 27, 9, "Argument of type \'number | null\' is not assignable to parameter of type \'number\'.\\n Type \'null\' is not assignable to type \'number\'.", "2171020380"], + [150, 8, 22, "Object is possibly \'undefined\'.", "2187394131"], + [156, 14, 18, "\'item.gridstackNode\' is possibly \'undefined\'.", "697090056"], + [242, 25, 23, "Argument of type \'[] | NgGridStackWidget[] | undefined\' is not assignable to parameter of type \'GridStackWidget[]\'.\\n Type \'undefined\' is not assignable to type \'GridStackWidget[]\'.", "90124799"], + [262, 27, 22, "Object is possibly \'undefined\'.", "2187394131"], + [264, 39, 32, "Argument of type \'number | null\' is not assignable to parameter of type \'number\'.\\n Type \'null\' is not assignable to type \'number\'.", "730256750"], + [274, 23, 32, "Argument of type \'number | null\' is not assignable to parameter of type \'number\'.\\n Type \'null\' is not assignable to type \'number\'.", "730256750"], + [285, 21, 22, "Object is possibly \'undefined\'.", "2187394131"], + [286, 9, 22, "Object is possibly \'undefined\'.", "2187394131"], + [511, 6, 4, "\'grid\' is possibly \'undefined\'.", "2087632733"], + [512, 6, 4, "\'grid\' is possibly \'undefined\'.", "2087632733"], + [515, 49, 4, "Argument of type \'GridStack | undefined\' is not assignable to parameter of type \'{ isAreaEmpty: (x: number, y: number, w: number, h: number) => boolean; willItFit: (w: NgGridStackWidget) => boolean; }\'.\\n Type \'undefined\' is not assignable to type \'{ isAreaEmpty: (x: number, y: number, w: number, h: number) => boolean; willItFit: (w: NgGridStackWidget) => boolean; }\'.", "2087632733"], + [526, 17, 22, "Object is possibly \'undefined\'.", "2187394131"], + [527, 8, 18, "\'item.gridstackNode\' is possibly \'undefined\'.", "697090056"], + [528, 6, 18, "\'item.gridstackNode\' is possibly \'undefined\'.", "697090056"], + [528, 6, 30, "\'item.gridstackNode.subGridOpts\' is possibly \'undefined\'.", "514924546"], + [528, 43, 18, "\'item.gridstackNode\' is possibly \'undefined\'.", "697090056"], + [528, 43, 30, "\'item.gridstackNode.subGridOpts\' is possibly \'undefined\'.", "514924546"], + [528, 83, 18, "\'item.gridstackNode\' is possibly \'undefined\'.", "697090056"], + [528, 83, 30, "\'item.gridstackNode.subGridOpts\' is possibly \'undefined\'.", "514924546"], + [528, 123, 18, "\'item.gridstackNode\' is possibly \'undefined\'.", "697090056"], + [567, 10, 22, "Object is possibly \'undefined\'.", "2187394131"], + [578, 14, 22, "Object is possibly \'undefined\'.", "2187394131"], + [585, 10, 6, "Type \'GridStackNode | undefined\' is not assignable to type \'NgGridStackWidget\'.\\n Type \'undefined\' is not assignable to type \'NgGridStackWidget\'.", "2169993400"], + [592, 16, 12, "\'source.input\' is possibly \'undefined\'.", "908845952"], + [594, 28, 12, "\'source.input\' is possibly \'undefined\'.", "908845952"], + [600, 8, 15, "\'_gridstack.grid\' is possibly \'undefined\'.", "3391422426"], + [601, 6, 15, "\'_gridstack.grid\' is possibly \'undefined\'.", "3391422426"], + [605, 10, 15, "\'_gridstack.grid\' is possibly \'undefined\'.", "3391422426"], + [606, 8, 15, "\'_gridstack.grid\' is possibly \'undefined\'.", "3391422426"], + [641, 8, 15, "\'_gridstack.grid\' is possibly \'undefined\'.", "3391422426"], + [642, 6, 15, "\'_gridstack.grid\' is possibly \'undefined\'.", "3391422426"], + [647, 10, 15, "\'_gridstack.grid\' is possibly \'undefined\'.", "3391422426"], + [648, 8, 15, "\'_gridstack.grid\' is possibly \'undefined\'.", "3391422426"], + [657, 4, 22, "Object is possibly \'undefined\'.", "2187394131"] + ], + "src/app/core/components/dashboards-editor/dashboards-editor.component.ts:976168273": [ + [80, 39, 40, "Argument of type \'string | undefined\' is not assignable to parameter of type \'string\'.\\n Type \'undefined\' is not assignable to type \'string\'.", "1983996063"], + [94, 6, 4, "Type \'string | undefined\' is not assignable to type \'string\'.\\n Type \'undefined\' is not assignable to type \'string\'.", "2087876002"], + [140, 17, 13, "\'currentActive\' is possibly \'null\'.", "194687392"], + [140, 56, 13, "\'currentActive\' is possibly \'null\'.", "194687392"], + [142, 44, 13, "\'currentActive\' is possibly \'null\'.", "194687392"], + [143, 17, 13, "\'currentActive\' is possibly \'null\'.", "194687392"], + [143, 56, 13, "\'currentActive\' is possibly \'null\'.", "194687392"], + [145, 44, 13, "\'currentActive\' is possibly \'null\'.", "194687392"] + ], + "src/app/core/components/data-inspector-row/data-inspector-row.component.ts:3525188709": [ + [25, 34, 9, "Argument of type \'undefined\' is not assignable to parameter of type \'string\'.", "2620553983"], + [34, 4, 10, "Type \'IConversionPathList\' is not assignable to type \'null\'.", "4013178488"], + [35, 24, 10, "Object is possibly \'null\'.", "4013178488"] + ], + "src/app/core/components/data-inspector/data-inspector.component.ts:2942185648": [ + [71, 4, 20, "Type \'Signal\' is not assignable to type \'Signal\'.\\n Type \'Signal\' is not assignable to type \'() => BreakpointState\'.\\n Type \'BreakpointState | undefined\' is not assignable to type \'BreakpointState\'.\\n Type \'undefined\' is not assignable to type \'BreakpointState\'.", "1507091964"] + ], + "src/app/core/components/group-widget/group-widget.component.ts:2421937404": [ + [85, 8, 6, "Type \'IWidgetSvcConfig | undefined\' is not assignable to type \'object\'.\\n Type \'undefined\' is not assignable to type \'object\'.", "1544266319"] + ], + "src/app/core/components/options/notifications/notifications.component.ts:3253454142": [ + [41, 4, 20, "Type \'Signal\' is not assignable to type \'Signal\'.\\n Type \'Signal\' is not assignable to type \'() => BreakpointState\'.\\n Type \'BreakpointState | undefined\' is not assignable to type \'BreakpointState\'.\\n Type \'undefined\' is not assignable to type \'BreakpointState\'.", "1507091964"], + [47, 4, 24, "Object is possibly \'undefined\'.", "2222700196"], + [54, 6, 17, "Object is possibly \'undefined\'.", "2944426029"], + [55, 6, 17, "Object is possibly \'undefined\'.", "27783321"] + ], + "src/app/core/components/options/signalk/signalk.component.ts:3522798646": [ + [101, 10, 6, "Type \'null\' is not assignable to type \'Chart\'.", "3491622934"], + [110, 45, 20, "Object is possibly \'undefined\'.", "235433357"], + [171, 28, 20, "Object is possibly \'undefined\'.", "235433357"], + [171, 28, 51, "Argument of type \'CanvasRenderingContext2D | null\' is not assignable to parameter of type \'ChartItem\'.\\n Type \'null\' is not assignable to type \'ChartItem\'.", "38422540"] + ], + "src/app/core/components/options/units/units.component.ts:2220224509": [ + [36, 19, 4, "Argument of type \'IUnit\' is not assignable to parameter of type \'never\'.", "2087995779"] + ], + "src/app/core/components/settings/settings.component.ts:794917258": [ + [23, 45, 23, "Object is possibly \'undefined\'.", "214257314"], + [24, 46, 24, "Object is possibly \'undefined\'.", "3441589046"] + ], + "src/app/core/components/widget-embedded/widget-embedded.component.ts:3928020917": [ + [114, 4, 13, "Type \'Type | undefined\' is not assignable to type \'Type\'.\\n Type \'undefined\' is not assignable to type \'Type\'.", "2689238020"] + ], + "src/app/core/components/widget-history-chart-dialog/widget-history-chart-dialog.component.ts:4108070123": [ + [221, 12, 1, "Type \'number | null\' is not assignable to type \'number\'.\\n Type \'null\' is not assignable to type \'number\'.", "177628"], + [284, 6, 12, "Object is possibly \'null\'.", "765689629"], + [285, 6, 12, "Object is possibly \'null\'.", "765689629"], + [286, 6, 12, "Object is possibly \'null\'.", "765689629"], + [287, 6, 12, "Object is possibly \'null\'.", "765689629"], + [288, 6, 12, "Object is possibly \'null\'.", "765689629"], + [289, 6, 12, "Object is possibly \'null\'.", "765689629"], + [290, 6, 12, "Object is possibly \'null\'.", "765689629"], + [291, 6, 12, "Object is possibly \'null\'.", "765689629"], + [305, 23, 12, "Object is possibly \'null\'.", "765689629"], + [306, 56, 6, "Property \'length\' does not exist on type \'never\'.", "1433765721"], + [418, 4, 6, "Type \'({ seriesId: string; datasetUuid: string; path: string; expansionMode: null; familyKey: null; allowedIds: null; trackedDevices?: null | undefined; ownerWidgetUuid: string; ownerWidgetSelector: string | null; ... 8 more ...; reconcileTs?: number | undefined; } | { ...; })[]\' is not assignable to type \'IKipSeriesDefinition[]\'.\\n Type \'{ seriesId: string; datasetUuid: string; path: string; expansionMode: null; familyKey: null; allowedIds: null; trackedDevices?: null | undefined; ownerWidgetUuid: string; ownerWidgetSelector: string | null; ... 8 more ...; reconcileTs?: number | undefined; } | { ...; }\' is not assignable to type \'IKipSeriesDefinition\'.\\n Type \'{ seriesId: string; datasetUuid: string; path: string; expansionMode: null; familyKey: null; allowedIds: null; ownerWidgetSelector: \\"widget-bms\\" | \\"widget-solar-charger\\" | \\"widget-charger\\" | \\"widget-inverter\\" | \\"widget-alternator\\" | \\"widget-ac\\"; ... 10 more ...; reconcileTs?: number; }\' is not assignable to type \'IKipSeriesDefinition\'.\\n Type \'{ seriesId: string; datasetUuid: string; path: string; expansionMode: null; familyKey: null; allowedIds: null; ownerWidgetSelector: \\"widget-bms\\" | \\"widget-solar-charger\\" | \\"widget-charger\\" | \\"widget-inverter\\" | \\"widget-alternator\\" | \\"widget-ac\\"; ... 10 more ...; reconcileTs?: number; }\' is not assignable to type \'IKipConcreteSeriesDefinition\'.\\n Types of property \'trackedDevices\' are incompatible.\\n Type \'readonly IElectricalTrackedDeviceRef[] | null | undefined\' is not assignable to type \'null | undefined\'.\\n Type \'readonly IElectricalTrackedDeviceRef[]\' is not assignable to type \'null | undefined\'.", "2123913871"], + [560, 21, 12, "Object is possibly \'null\'.", "765689629"], + [563, 21, 12, "Object is possibly \'null\'.", "765689629"], + [571, 21, 12, "Object is possibly \'null\'.", "765689629"], + [590, 59, 12, "Object is possibly \'null\'.", "765689629"], + [643, 19, 12, "Object is possibly \'null\'.", "765689629"], + [646, 19, 12, "Object is possibly \'null\'.", "765689629"], + [651, 19, 12, "Object is possibly \'null\'.", "765689629"], + [664, 10, 12, "Object is possibly \'null\'.", "765689629"], + [672, 17, 12, "Object is possibly \'null\'.", "765689629"], + [676, 17, 12, "Object is possibly \'null\'.", "765689629"], + [705, 4, 6, "Type \'{ fillStyle: Color; lineDash: _DeepPartialArray; text: string; borderRadius?: number | BorderRadius | undefined; datasetIndex?: number | undefined; ... 10 more ...; textAlign?: TextAlign | undefined; }[]\' is not assignable to type \'LegendItem[]\'.\\n Type \'{ fillStyle: Color; lineDash: _DeepPartialArray; text: string; borderRadius?: number | BorderRadius; datasetIndex?: number; ... 10 more ...; textAlign?: TextAlign; }\' is not assignable to type \'LegendItem\'.\\n Types of property \'lineDash\' are incompatible.\\n Type \'_DeepPartialArray\' is not assignable to type \'number[]\'.\\n Type \'number | undefined\' is not assignable to type \'number\'.\\n Type \'undefined\' is not assignable to type \'number\'.", "2123913871"] + ], + "src/app/core/components/widget-host2/widget-host2.component.ts:867588761": [ + [137, 4, 13, "Type \'Type | undefined\' is not assignable to type \'Type\'.\\n Type \'undefined\' is not assignable to type \'Type\'.", "2689238020"], + [253, 32, 9, "Type \'null\' cannot be used as an index type.", "2171020380"] + ], + "src/app/core/components/widget-title/widget-title.component.ts:2551944470": [ + [25, 4, 14, "Type \'CanvasRenderingContext2D | null\' is not assignable to type \'CanvasRenderingContext2D\'.\\n Type \'null\' is not assignable to type \'CanvasRenderingContext2D\'.", "912271434"], + [54, 4, 14, "Type \'null\' is not assignable to type \'CanvasRenderingContext2D\'.", "912271434"], + [55, 4, 18, "Type \'null\' is not assignable to type \'HTMLCanvasElement\'.", "1193423419"] + ], + "src/app/core/utils/dataScales.util.ts:2208923770": [ + [54, 6, 12, "Type \'null\' is not assignable to type \'number\'.", "2083421902"] + ], + "src/app/core/utils/zones-highlight.utils.ts:1634660371": [ + [42, 8, 5, "Type \'null\' is not assignable to type \'number\'.", "173263814"], + [43, 8, 5, "Type \'null\' is not assignable to type \'number\'.", "183473191"], + [72, 6, 5, "Type \'number | null\' is not assignable to type \'number\'.\\n Type \'null\' is not assignable to type \'number\'.", "173263814"], + [78, 6, 5, "Type \'number | null\' is not assignable to type \'number\'.\\n Type \'null\' is not assignable to type \'number\'.", "183473191"] + ], + "src/app/widget-config/boolean-control-config/boolean-control-config.component.ts:3033536446": [ + [25, 40, 9, "Argument of type \'undefined\' is not assignable to parameter of type \'number\'.", "2620553983"], + [26, 39, 9, "Argument of type \'undefined\' is not assignable to parameter of type \'number\'.", "2620553983"], + [33, 4, 11, "Type \'{ label: string; value: string; }[]\' is not assignable to type \'never[]\'.\\n Type \'{ label: string; value: string; }\' is not assignable to type \'never\'.", "3027418051"], + [37, 79, 34, "Object is possibly \'null\'.", "3704244789"] + ], + "src/app/widget-config/boolean-multicontrol-options/boolean-multicontrol-options.component.ts:1795746450": [ + [35, 9, 14, "Type \'null\' is not assignable to type \'UntypedFormGroup\'.", "3522031013"], + [37, 10, 26, "Type \'null\' is not assignable to type \'Subscription\'.", "273497119"], + [79, 8, 13, "Type \'null\' is not assignable to type \'string | undefined\'.", "2466344431"] + ], + "src/app/widget-config/dataset-chart-options/dataset-chart-options.component.ts:2604195000": [ + [82, 26, 10, "Argument of type \'ISkPathData | null\' is not assignable to parameter of type \'ISkPathData\'.\\n Type \'null\' is not assignable to type \'ISkPathData\'.", "384538813"] + ], + "src/app/widget-config/display-chart-options/display-chart-options.component.ts:333710162": [ + [48, 4, 11, "Type \'{ label: string; value: string; }[]\' is not assignable to type \'never[]\'.\\n Type \'{ label: string; value: string; }\' is not assignable to type \'never\'.", "3027418051"] + ], + "src/app/widget-config/display-datetime/display-datetime.component.ts:1505324315": [ + [45, 50, 9, "Argument of type \'undefined\' is not assignable to parameter of type \'UntypedFormControl\'.", "2620553983"], + [46, 52, 9, "Argument of type \'undefined\' is not assignable to parameter of type \'UntypedFormControl\'.", "2620553983"], + [49, 10, 22, "Type \'null\' is not assignable to type \'Subscription\'.", "29842089"] + ], + "src/app/widget-config/electrical-family-setup/electrical-family-setup.component.ts:4115844403": [ + [60, 48, 28, "Object is possibly \'undefined\'.", "758680035"], + [114, 4, 20, "Object is possibly \'undefined\'.", "2522653710"], + [115, 4, 20, "Object is possibly \'undefined\'.", "2522653710"], + [119, 4, 20, "Object is possibly \'undefined\'.", "2522653710"], + [120, 4, 20, "Object is possibly \'undefined\'.", "2522653710"] + ], + "src/app/widget-config/paths-options/paths-options.component.ts:3600643100": [ + [31, 51, 9, "Argument of type \'undefined\' is not assignable to parameter of type \'IAddNewPathObject\'.", "2620553983"], + [32, 40, 9, "Argument of type \'undefined\' is not assignable to parameter of type \'string\'.", "2620553983"], + [33, 54, 9, "Argument of type \'undefined\' is not assignable to parameter of type \'IDynamicControl[]\'.", "2620553983"], + [42, 28, 49, "Object is possibly \'null\'.", "3725617003"], + [66, 26, 49, "Object is possibly \'null\'.", "3725617003"], + [70, 26, 49, "Object is possibly \'null\'.", "3725617003"] + ], + "src/app/widget-config/root-modal-widget-config/root-modal-widget-config.component.ts:2942117481": [ + [74, 4, 11, "Type \'{ label: string; value: string; }[]\' is not assignable to type \'never[]\'.\\n Type \'{ label: string; value: string; }\' is not assignable to type \'never\'.", "3027418051"], + [181, 8, 4, "Type \'null\' is not assignable to type \'UntypedFormControl\'.", "2087777580"], + [202, 4, 9, "\'ctrlLabel\' is possibly \'null\'.", "2892925034"] + ], + "src/app/widget-config/solar-charger-setup/solar-charger-setup.component.ts:3993417046": [ + [47, 48, 28, "Object is possibly \'undefined\'.", "758680035"], + [151, 4, 20, "Object is possibly \'undefined\'.", "2522653710"], + [152, 4, 20, "Object is possibly \'undefined\'.", "2522653710"], + [156, 4, 20, "Object is possibly \'undefined\'.", "2522653710"], + [157, 4, 20, "Object is possibly \'undefined\'.", "2522653710"] + ], + "src/app/widgets/gauge-steel/gauge-steel.component.ts:3394617356": [ + [74, 38, 9, "Argument of type \'undefined\' is not assignable to parameter of type \'string\'.", "2620553983"], + [75, 35, 9, "Argument of type \'undefined\' is not assignable to parameter of type \'string\'.", "2620553983"], + [76, 37, 9, "Argument of type \'undefined\' is not assignable to parameter of type \'boolean\'.", "2620553983"], + [77, 38, 9, "Argument of type \'undefined\' is not assignable to parameter of type \'string\'.", "2620553983"], + [78, 43, 9, "Argument of type \'undefined\' is not assignable to parameter of type \'string\'.", "2620553983"], + [79, 38, 9, "Argument of type \'undefined\' is not assignable to parameter of type \'string\'.", "2620553983"], + [80, 36, 9, "Argument of type \'undefined\' is not assignable to parameter of type \'number\'.", "2620553983"], + [81, 36, 9, "Argument of type \'undefined\' is not assignable to parameter of type \'number\'.", "2620553983"], + [82, 36, 9, "Argument of type \'undefined\' is not assignable to parameter of type \'number\'.", "2620553983"], + [83, 36, 9, "Argument of type \'undefined\' is not assignable to parameter of type \'ISkZone[]\'.", "2620553983"], + [84, 33, 9, "Argument of type \'undefined\' is not assignable to parameter of type \'string\'.", "2620553983"], + [85, 33, 9, "Argument of type \'undefined\' is not assignable to parameter of type \'string\'.", "2620553983"], + [86, 33, 9, "Argument of type \'undefined\' is not assignable to parameter of type \'number\'.", "2620553983"], + [127, 52, 7, "\'a.lower\' is possibly \'undefined\'.", "2967727561"], + [127, 62, 7, "\'b.lower\' is possibly \'undefined\'.", "4173952970"], + [130, 12, 5, "Type \'null\' is not assignable to type \'number\'.", "173263814"], + [131, 12, 5, "Type \'null\' is not assignable to type \'number\'.", "183473191"], + [136, 20, 12, "Object is possibly \'undefined\'.", "765689629"], + [139, 20, 12, "Object is possibly \'undefined\'.", "765689629"], + [142, 20, 12, "Object is possibly \'undefined\'.", "765689629"], + [145, 20, 12, "Object is possibly \'undefined\'.", "765689629"], + [148, 20, 12, "Object is possibly \'undefined\'.", "765689629"], + [157, 10, 5, "Type \'number | undefined\' is not assignable to type \'number\'.\\n Type \'undefined\' is not assignable to type \'number\'.", "173263814"], + [158, 10, 5, "Type \'number | undefined\' is not assignable to type \'number\'.\\n Type \'undefined\' is not assignable to type \'number\'.", "183473191"], + [160, 10, 5, "Type \'number | null\' is not assignable to type \'number\'.\\n Type \'null\' is not assignable to type \'number\'.", "173263814"], + [160, 57, 10, "Argument of type \'number | undefined\' is not assignable to parameter of type \'number\'.\\n Type \'undefined\' is not assignable to type \'number\'.", "467412886"], + [161, 10, 5, "Type \'number | null\' is not assignable to type \'number\'.\\n Type \'null\' is not assignable to type \'number\'.", "183473191"], + [161, 57, 10, "Argument of type \'number | undefined\' is not assignable to parameter of type \'number\'.\\n Type \'undefined\' is not assignable to type \'number\'.", "440544247"], + [179, 24, 40, "Argument of type \'any\' is not assignable to parameter of type \'never\'.", "1277859535"], + [183, 22, 40, "Argument of type \'any\' is not assignable to parameter of type \'never\'.", "1277859535"] + ], + "src/app/widgets/minichart/minichart.component.ts:15445999": [ + [43, 9, 5, "Type \'null\' is not assignable to type \'string\'.", "176948952"], + [44, 9, 8, "Type \'null\' is not assignable to type \'string\'.", "806402680"], + [45, 9, 10, "Type \'null\' is not assignable to type \'string\'.", "1967398792"], + [46, 9, 13, "Type \'null\' is not assignable to type \'string\'.", "2466344431"], + [47, 9, 10, "Type \'null\' is not assignable to type \'number\'.", "2101602424"], + [48, 9, 9, "Type \'null\' is not assignable to type \'number\'.", "212862030"], + [49, 9, 9, "Type \'null\' is not assignable to type \'number\'.", "212862288"], + [77, 10, 9, "Type \'null\' is not assignable to type \'Subscription\'.", "4113745821"], + [78, 10, 14, "Type \'null\' is not assignable to type \'IChartDataSourceInfo\'.", "2985720646"], + [152, 4, 21, "Object is possibly \'undefined\'.", "406043295"], + [153, 4, 21, "Object is possibly \'undefined\'.", "406043295"], + [155, 4, 21, "Object is possibly \'undefined\'.", "406043295"], + [158, 6, 21, "Object is possibly \'undefined\'.", "406043295"], + [162, 10, 12, "Type \'number | null\' is not assignable to type \'number | undefined\'.\\n Type \'null\' is not assignable to type \'number | undefined\'.", "3614877034"], + [163, 10, 12, "Type \'number | null\' is not assignable to type \'number | undefined\'.\\n Type \'null\' is not assignable to type \'number | undefined\'.", "3614877300"], + [164, 10, 3, "Type \'number | null\' is not assignable to type \'number | undefined\'.\\n Type \'null\' is not assignable to type \'number | undefined\'.", "193413807"], + [165, 10, 3, "Type \'number | null\' is not assignable to type \'number | undefined\'.\\n Type \'null\' is not assignable to type \'number | undefined\'.", "193414065"], + [219, 6, 21, "Object is possibly \'undefined\'.", "406043295"], + [254, 10, 12, "Type \'number | null\' is not assignable to type \'number | undefined\'.\\n Type \'null\' is not assignable to type \'number | undefined\'.", "3614877034"], + [255, 10, 12, "Type \'number | null\' is not assignable to type \'number | undefined\'.\\n Type \'null\' is not assignable to type \'number | undefined\'.", "3614877300"], + [256, 10, 3, "Type \'number | null\' is not assignable to type \'number | undefined\'.\\n Type \'null\' is not assignable to type \'number | undefined\'.", "193413807"], + [257, 10, 3, "Type \'number | null\' is not assignable to type \'number | undefined\'.\\n Type \'null\' is not assignable to type \'number | undefined\'.", "193414065"], + [281, 4, 21, "Object is possibly \'undefined\'.", "406043295"], + [294, 26, 21, "Object is possibly \'undefined\'.", "406043295"], + [339, 6, 9, "Type \'null\' is not assignable to type \'string\'.", "384690336"], + [340, 6, 9, "Type \'null\' is not assignable to type \'string\'.", "384749729"], + [341, 6, 11, "Type \'null\' is not assignable to type \'string\'.", "936435848"], + [342, 6, 11, "Type \'null\' is not assignable to type \'string\'.", "935954057"], + [343, 6, 16, "Type \'null\' is not assignable to type \'string\'.", "505309252"], + [344, 6, 10, "Type \'null\' is not assignable to type \'string\'.", "1290121711"], + [345, 6, 10, "Type \'null\' is not assignable to type \'string\'.", "1316340194"], + [546, 4, 14, "Type \'null\' is not assignable to type \'Subscription\'.", "2516429621"], + [558, 4, 6, "Type \'({ x: number | null; y: number; } | { x: number; y: number | null; })[]\' is not assignable to type \'IDataSetRow[]\'.\\n Type \'{ x: number | null; y: number; } | { x: number; y: number | null; }\' is not assignable to type \'IDataSetRow\'.\\n Type \'{ x: number | null; y: number; }\' is not assignable to type \'IDataSetRow\'.\\n Types of property \'x\' are incompatible.\\n Type \'number | null\' is not assignable to type \'number\'.\\n Type \'null\' is not assignable to type \'number\'.", "2123913871"] + ], + "src/app/widgets/svg-boolean-button/svg-boolean-button.component.ts:1543445686": [ + [14, 41, 4, "No overload matches this call.\\n Overload 1 of 5, \'(initialValue: IDynamicControl, opts?: InputOptionsWithoutTransform | undefined): InputSignal<...>\', gave the following error.\\n Argument of type \'null\' is not assignable to parameter of type \'IDynamicControl\'.\\n Overload 2 of 5, \'(initialValue: undefined, opts: InputOptionsWithoutTransform): InputSignal\', gave the following error.\\n Argument of type \'null\' is not assignable to parameter of type \'undefined\'.", "2087897566"], + [15, 33, 4, "Argument of type \'null\' is not assignable to parameter of type \'ITheme\'.", "2087897566"], + [21, 10, 8, "Type \'null\' is not assignable to type \'ITheme\'.", "2459887219"], + [114, 8, 22, "Type \'\\"black\\"\' is not assignable to type \'null\'.", "807528371"], + [115, 8, 23, "Type \'string\' is not assignable to type \'null\'.", "2686791206"], + [116, 8, 15, "Type \'string\' is not assignable to type \'null\'.", "1525246139"], + [119, 8, 22, "Type \'string\' is not assignable to type \'null\'.", "807528371"], + [120, 8, 23, "Type \'string\' is not assignable to type \'null\'.", "2686791206"], + [121, 8, 15, "Type \'string\' is not assignable to type \'null\'.", "1525246139"], + [124, 8, 22, "Type \'string\' is not assignable to type \'null\'.", "807528371"], + [125, 8, 23, "Type \'string\' is not assignable to type \'null\'.", "2686791206"], + [126, 8, 15, "Type \'string\' is not assignable to type \'null\'.", "1525246139"], + [129, 8, 22, "Type \'string\' is not assignable to type \'null\'.", "807528371"], + [130, 8, 23, "Type \'string\' is not assignable to type \'null\'.", "2686791206"], + [131, 8, 15, "Type \'string\' is not assignable to type \'null\'.", "1525246139"], + [134, 8, 22, "Type \'string\' is not assignable to type \'null\'.", "807528371"], + [135, 8, 23, "Type \'string\' is not assignable to type \'null\'.", "2686791206"], + [136, 8, 15, "Type \'string\' is not assignable to type \'null\'.", "1525246139"], + [139, 8, 22, "Type \'string\' is not assignable to type \'null\'.", "807528371"], + [140, 8, 23, "Type \'string\' is not assignable to type \'null\'.", "2686791206"], + [141, 8, 15, "Type \'string\' is not assignable to type \'null\'.", "1525246139"], + [144, 8, 22, "Type \'string\' is not assignable to type \'null\'.", "807528371"], + [145, 8, 23, "Type \'string\' is not assignable to type \'null\'.", "2686791206"], + [146, 8, 15, "Type \'string\' is not assignable to type \'null\'.", "1525246139"], + [149, 8, 22, "Type \'string\' is not assignable to type \'null\'.", "807528371"], + [150, 8, 23, "Type \'string\' is not assignable to type \'null\'.", "2686791206"], + [151, 8, 15, "Type \'string\' is not assignable to type \'null\'.", "1525246139"], + [154, 8, 22, "Type \'\\"black\\"\' is not assignable to type \'null\'.", "807528371"], + [155, 8, 23, "Type \'string\' is not assignable to type \'null\'.", "2686791206"], + [156, 8, 15, "Type \'string\' is not assignable to type \'null\'.", "1525246139"] + ], + "src/app/widgets/svg-boolean-light/svg-boolean-light.component.ts:520976916": [ + [15, 41, 4, "No overload matches this call.\\n Overload 1 of 5, \'(initialValue: IDynamicControl, opts?: InputOptionsWithoutTransform | undefined): InputSignal<...>\', gave the following error.\\n Argument of type \'null\' is not assignable to parameter of type \'IDynamicControl\'.\\n Overload 2 of 5, \'(initialValue: undefined, opts: InputOptionsWithoutTransform): InputSignal\', gave the following error.\\n Argument of type \'null\' is not assignable to parameter of type \'undefined\'.", "2087897566"], + [16, 33, 4, "Argument of type \'null\' is not assignable to parameter of type \'ITheme\'.", "2087897566"], + [22, 10, 9, "Type \'null\' is not assignable to type \'boolean\'.", "2931300859"], + [24, 10, 8, "Type \'null\' is not assignable to type \'ITheme\'.", "2459887219"], + [59, 8, 15, "Type \'string\' is not assignable to type \'null\'.", "2145130966"], + [60, 8, 15, "Type \'string\' is not assignable to type \'null\'.", "1525246139"], + [63, 8, 15, "Type \'string\' is not assignable to type \'null\'.", "2145130966"], + [64, 8, 15, "Type \'string\' is not assignable to type \'null\'.", "1525246139"], + [67, 8, 15, "Type \'string\' is not assignable to type \'null\'.", "2145130966"], + [68, 8, 15, "Type \'string\' is not assignable to type \'null\'.", "1525246139"], + [71, 8, 15, "Type \'string\' is not assignable to type \'null\'.", "2145130966"], + [72, 8, 15, "Type \'string\' is not assignable to type \'null\'.", "1525246139"], + [75, 8, 15, "Type \'string\' is not assignable to type \'null\'.", "2145130966"], + [76, 8, 15, "Type \'string\' is not assignable to type \'null\'.", "1525246139"], + [79, 8, 15, "Type \'string\' is not assignable to type \'null\'.", "2145130966"], + [80, 8, 15, "Type \'string\' is not assignable to type \'null\'.", "1525246139"], + [83, 8, 15, "Type \'string\' is not assignable to type \'null\'.", "2145130966"], + [84, 8, 15, "Type \'string\' is not assignable to type \'null\'.", "1525246139"], + [87, 8, 15, "Type \'string\' is not assignable to type \'null\'.", "2145130966"], + [88, 8, 15, "Type \'string\' is not assignable to type \'null\'.", "1525246139"], + [91, 8, 15, "Type \'string\' is not assignable to type \'null\'.", "2145130966"], + [92, 8, 15, "Type \'string\' is not assignable to type \'null\'.", "1525246139"] + ], + "src/app/widgets/svg-boolean-switch/svg-boolean-switch.component.ts:1706226148": [ + [13, 41, 4, "No overload matches this call.\\n Overload 1 of 5, \'(initialValue: IDynamicControl, opts?: InputOptionsWithoutTransform | undefined): InputSignal<...>\', gave the following error.\\n Argument of type \'null\' is not assignable to parameter of type \'IDynamicControl\'.\\n Overload 2 of 5, \'(initialValue: undefined, opts: InputOptionsWithoutTransform): InputSignal\', gave the following error.\\n Argument of type \'null\' is not assignable to parameter of type \'undefined\'.", "2087897566"], + [14, 33, 4, "Argument of type \'null\' is not assignable to parameter of type \'ITheme\'.", "2087897566"], + [20, 10, 9, "Type \'null\' is not assignable to type \'boolean\'.", "2931300859"], + [21, 10, 8, "Type \'null\' is not assignable to type \'ITheme\'.", "2459887219"], + [75, 8, 15, "Type \'string\' is not assignable to type \'null\'.", "2145130966"], + [76, 8, 15, "Type \'string\' is not assignable to type \'null\'.", "1525246139"], + [79, 8, 15, "Type \'string\' is not assignable to type \'null\'.", "2145130966"], + [80, 8, 15, "Type \'string\' is not assignable to type \'null\'.", "1525246139"], + [83, 8, 15, "Type \'string\' is not assignable to type \'null\'.", "2145130966"], + [84, 8, 15, "Type \'string\' is not assignable to type \'null\'.", "1525246139"], + [87, 8, 15, "Type \'string\' is not assignable to type \'null\'.", "2145130966"], + [88, 8, 15, "Type \'string\' is not assignable to type \'null\'.", "1525246139"], + [91, 8, 15, "Type \'string\' is not assignable to type \'null\'.", "2145130966"], + [92, 8, 15, "Type \'string\' is not assignable to type \'null\'.", "1525246139"], + [95, 8, 15, "Type \'string\' is not assignable to type \'null\'.", "2145130966"], + [96, 8, 15, "Type \'string\' is not assignable to type \'null\'.", "1525246139"], + [99, 8, 15, "Type \'string\' is not assignable to type \'null\'.", "2145130966"], + [100, 8, 15, "Type \'string\' is not assignable to type \'null\'.", "1525246139"], + [103, 8, 15, "Type \'string\' is not assignable to type \'null\'.", "2145130966"], + [104, 8, 15, "Type \'string\' is not assignable to type \'null\'.", "1525246139"], + [107, 8, 15, "Type \'string\' is not assignable to type \'null\'.", "2145130966"], + [108, 8, 15, "Type \'string\' is not assignable to type \'null\'.", "1525246139"] + ], + "src/app/widgets/svg-racesteer/svg-racesteer.component.ts:3776013780": [ + [36, 46, 9, "Argument of type \'undefined\' is not assignable to parameter of type \'number\'.", "2620553983"], + [37, 47, 9, "Argument of type \'undefined\' is not assignable to parameter of type \'number\'.", "2620553983"], + [39, 51, 9, "Argument of type \'undefined\' is not assignable to parameter of type \'number\'.", "2620553983"], + [40, 51, 9, "Argument of type \'undefined\' is not assignable to parameter of type \'number\'.", "2620553983"], + [41, 57, 9, "Argument of type \'undefined\' is not assignable to parameter of type \'number\'.", "2620553983"], + [42, 57, 9, "Argument of type \'undefined\' is not assignable to parameter of type \'number\'.", "2620553983"], + [43, 57, 9, "Argument of type \'undefined\' is not assignable to parameter of type \'number\'.", "2620553983"] + ], + "src/app/widgets/svg-windsteer/svg-windsteer.component.ts:3669162095": [ + [28, 59, 9, "Argument of type \'undefined\' is not assignable to parameter of type \'number\'.", "2620553983"], + [39, 50, 9, "Argument of type \'undefined\' is not assignable to parameter of type \'number\'.", "2620553983"], + [44, 46, 9, "Argument of type \'undefined\' is not assignable to parameter of type \'number\'.", "2620553983"], + [45, 47, 9, "Argument of type \'undefined\' is not assignable to parameter of type \'number\'.", "2620553983"], + [46, 51, 9, "Argument of type \'undefined\' is not assignable to parameter of type \'number\'.", "2620553983"], + [48, 57, 9, "Argument of type \'undefined\' is not assignable to parameter of type \'number\'.", "2620553983"], + [49, 57, 9, "Argument of type \'undefined\' is not assignable to parameter of type \'number\'.", "2620553983"], + [50, 57, 9, "Argument of type \'undefined\' is not assignable to parameter of type \'number\'.", "2620553983"] + ], + "src/app/widgets/svg-zone-states/svg-zone-states.component.ts:1762718998": [ + [17, 41, 4, "No overload matches this call.\\n Overload 1 of 5, \'(initialValue: IDynamicControl, opts?: InputOptionsWithoutTransform | undefined): InputSignal<...>\', gave the following error.\\n Argument of type \'null\' is not assignable to parameter of type \'IDynamicControl\'.\\n Overload 2 of 5, \'(initialValue: undefined, opts: InputOptionsWithoutTransform): InputSignal\', gave the following error.\\n Argument of type \'null\' is not assignable to parameter of type \'undefined\'.", "2087897566"], + [18, 33, 4, "Argument of type \'null\' is not assignable to parameter of type \'ITheme\'.", "2087897566"], + [22, 41, 4, "Argument of type \'null\' is not assignable to parameter of type \'string\'.", "2087897566"], + [23, 41, 4, "Argument of type \'null\' is not assignable to parameter of type \'string\'.", "2087897566"], + [24, 42, 4, "Argument of type \'null\' is not assignable to parameter of type \'string\'.", "2087897566"] + ], + "src/app/widgets/widget-ais-radar/dialog-ais-target/dialog-ais-target.component.ts:2335594053": [ + [41, 11, 38, "Object is possibly \'null\'.", "3959613788"], + [46, 14, 37, "Object is possibly \'null\'.", "1171285017"], + [85, 11, 34, "Object is possibly \'null\'.", "4280675262"] + ], + "src/app/widgets/widget-ais-radar/widget-ais-radar.component.ts:4016173371": [ + [416, 34, 9, "Argument of type \'string | undefined\' is not assignable to parameter of type \'string\'.\\n Type \'undefined\' is not assignable to type \'string\'.", "4119212820"], + [543, 29, 17, "Object is possibly \'undefined\'.", "671087258"], + [738, 49, 14, "Argument of type \'Position | undefined\' is not assignable to parameter of type \'Position\'.\\n Type \'undefined\' is not assignable to type \'Position\'.", "3448801501"], + [739, 56, 14, "Argument of type \'Position | undefined\' is not assignable to parameter of type \'Position\'.\\n Type \'undefined\' is not assignable to type \'Position\'.", "3448801501"], + [762, 8, 6, "Type \'string | undefined\' is not assignable to type \'string\'.\\n Type \'undefined\' is not assignable to type \'string\'.", "2141063537"], + [774, 8, 6, "Type \'string | undefined\' is not assignable to type \'string\'.\\n Type \'undefined\' is not assignable to type \'string\'.", "2141063537"], + [1350, 17, 10, "\'a.latitude\' is possibly \'undefined\'.", "3625974138"], + [1351, 17, 10, "\'b.latitude\' is possibly \'undefined\'.", "3132265881"], + [1352, 18, 10, "\'b.latitude\' is possibly \'undefined\'.", "3132265881"], + [1352, 31, 10, "\'a.latitude\' is possibly \'undefined\'.", "3625974138"], + [1353, 21, 11, "\'b.longitude\' is possibly \'undefined\'.", "3370058570"], + [1353, 35, 11, "\'a.longitude\' is possibly \'undefined\'.", "2985066057"] + ], + "src/app/widgets/widget-autopilot/widget-autopilot.component.ts:2942713930": [ + [275, 6, 10, "Type \'null\' is not assignable to type \'\\"v1\\" | \\"v2\\"\'.", "2208951047"], + [324, 23, 22, "Object is possibly \'undefined\'.", "576852750"], + [324, 23, 32, "Object is possibly \'undefined\'.", "525756929"], + [336, 23, 22, "Object is possibly \'undefined\'.", "576852750"], + [336, 23, 32, "Object is possibly \'undefined\'.", "525756929"], + [341, 47, 5, "Argument of type \'string | null\' is not assignable to parameter of type \'string\'.\\n Type \'null\' is not assignable to type \'string\'.", "195031250"], + [351, 23, 22, "Object is possibly \'undefined\'.", "576852750"], + [351, 23, 32, "Object is possibly \'undefined\'.", "525756929"], + [363, 77, 4, "Argument of type \'string | null\' is not assignable to parameter of type \'string\'.\\n Type \'null\' is not assignable to type \'string\'.", "2087698470"], + [370, 77, 4, "Argument of type \'string | null\' is not assignable to parameter of type \'string\'.\\n Type \'null\' is not assignable to type \'string\'.", "2087698470"], + [401, 23, 22, "Object is possibly \'undefined\'.", "576852750"], + [401, 23, 32, "Object is possibly \'undefined\'.", "525756929"], + [413, 52, 4, "Argument of type \'string | null\' is not assignable to parameter of type \'string\'.\\n Type \'null\' is not assignable to type \'string\'.", "2087698470"], + [421, 52, 4, "Argument of type \'string | null\' is not assignable to parameter of type \'string\'.\\n Type \'null\' is not assignable to type \'string\'.", "2087698470"], + [612, 23, 22, "Object is possibly \'undefined\'.", "576852750"], + [612, 23, 32, "Object is possibly \'undefined\'.", "525756929"], + [613, 23, 22, "Object is possibly \'undefined\'.", "576852750"], + [613, 23, 32, "Object is possibly \'undefined\'.", "525756929"], + [614, 21, 22, "Object is possibly \'undefined\'.", "576852750"], + [614, 21, 32, "Object is possibly \'undefined\'.", "525756929"], + [674, 18, 22, "Object is possibly \'undefined\'.", "576852750"], + [674, 18, 32, "Object is possibly \'undefined\'.", "525756929"], + [688, 4, 12, "Object is possibly \'null\'.", "4261782498"], + [696, 4, 12, "Object is possibly \'null\'.", "4261782498"], + [704, 4, 12, "Object is possibly \'null\'.", "4261782498"], + [712, 4, 12, "Object is possibly \'null\'.", "4261782498"], + [726, 4, 22, "Object is possibly \'undefined\'.", "576852750"], + [726, 4, 28, "Object is possibly \'undefined\'.", "3500113022"], + [727, 4, 12, "Object is possibly \'null\'.", "4261782498"], + [735, 4, 12, "Object is possibly \'null\'.", "4261782498"], + [736, 4, 12, "Object is possibly \'null\'.", "4261782498"], + [747, 4, 12, "Object is possibly \'null\'.", "4261782498"], + [748, 4, 12, "Object is possibly \'null\'.", "4261782498"], + [752, 26, 22, "Object is possibly \'undefined\'.", "576852750"], + [752, 26, 32, "Object is possibly \'undefined\'.", "525756929"], + [757, 8, 22, "Object is possibly \'undefined\'.", "576852750"], + [757, 8, 32, "Object is possibly \'undefined\'.", "525756929"], + [758, 6, 12, "Object is possibly \'null\'.", "4261782498"], + [760, 6, 12, "Object is possibly \'null\'.", "4261782498"], + [763, 4, 12, "Object is possibly \'null\'.", "4261782498"], + [801, 10, 22, "Object is possibly \'undefined\'.", "576852750"], + [801, 10, 32, "Object is possibly \'undefined\'.", "525756929"], + [834, 23, 22, "Object is possibly \'undefined\'.", "576852750"], + [834, 23, 32, "Object is possibly \'undefined\'.", "525756929"], + [1016, 10, 8, "Variable \'response\' is used before being assigned.", "2137101542"], + [1020, 104, 8, "Variable \'response\' is used before being assigned.", "2137101542"], + [1021, 15, 8, "Variable \'response\' is used before being assigned.", "2137101542"], + [1059, 8, 22, "Object is possibly \'undefined\'.", "576852750"], + [1059, 8, 32, "Object is possibly \'undefined\'.", "525756929"], + [1072, 8, 22, "Object is possibly \'undefined\'.", "576852750"], + [1072, 8, 32, "Object is possibly \'undefined\'.", "525756929"], + [1081, 8, 22, "Object is possibly \'undefined\'.", "576852750"], + [1081, 8, 32, "Object is possibly \'undefined\'.", "525756929"], + [1133, 17, 31, "No overload matches this call.\\n Overload 1 of 2, \'(timeout: string | number | Timeout | undefined): void\', gave the following error.\\n Argument of type \'Timeout | null\' is not assignable to parameter of type \'string | number | Timeout | undefined\'.\\n Type \'null\' is not assignable to type \'string | number | Timeout | undefined\'.\\n Overload 2 of 2, \'(id: number | undefined): void\', gave the following error.\\n Argument of type \'Timeout | null\' is not assignable to parameter of type \'number | undefined\'.\\n Type \'null\' is not assignable to type \'number | undefined\'.", "315042064"], + [1143, 17, 31, "No overload matches this call.\\n Overload 1 of 2, \'(timeout: string | number | Timeout | undefined): void\', gave the following error.\\n Argument of type \'Timeout | null\' is not assignable to parameter of type \'string | number | Timeout | undefined\'.\\n Type \'null\' is not assignable to type \'string | number | Timeout | undefined\'.\\n Overload 2 of 2, \'(id: number | undefined): void\', gave the following error.\\n Argument of type \'Timeout | null\' is not assignable to parameter of type \'number | undefined\'.\\n Type \'null\' is not assignable to type \'number | undefined\'.", "315042064"], + [1144, 17, 34, "No overload matches this call.\\n Overload 1 of 2, \'(timeout: string | number | Timeout | undefined): void\', gave the following error.\\n Argument of type \'Timeout | null\' is not assignable to parameter of type \'string | number | Timeout | undefined\'.\\n Type \'null\' is not assignable to type \'string | number | Timeout | undefined\'.\\n Overload 2 of 2, \'(id: number | undefined): void\', gave the following error.\\n Argument of type \'Timeout | null\' is not assignable to parameter of type \'number | undefined\'.\\n Type \'null\' is not assignable to type \'number | undefined\'.", "4009237785"], + [1153, 19, 34, "No overload matches this call.\\n Overload 1 of 2, \'(timeout: string | number | Timeout | undefined): void\', gave the following error.\\n Argument of type \'Timeout | null\' is not assignable to parameter of type \'string | number | Timeout | undefined\'.\\n Type \'null\' is not assignable to type \'string | number | Timeout | undefined\'.\\n Overload 2 of 2, \'(id: number | undefined): void\', gave the following error.\\n Argument of type \'Timeout | null\' is not assignable to parameter of type \'number | undefined\'.\\n Type \'null\' is not assignable to type \'number | undefined\'.", "4009237785"], + [1161, 21, 34, "No overload matches this call.\\n Overload 1 of 2, \'(timeout: string | number | Timeout | undefined): void\', gave the following error.\\n Argument of type \'Timeout | null\' is not assignable to parameter of type \'string | number | Timeout | undefined\'.\\n Type \'null\' is not assignable to type \'string | number | Timeout | undefined\'.\\n Overload 2 of 2, \'(id: number | undefined): void\', gave the following error.\\n Argument of type \'Timeout | null\' is not assignable to parameter of type \'number | undefined\'.\\n Type \'null\' is not assignable to type \'number | undefined\'.", "4009237785"], + [1179, 17, 30, "No overload matches this call.\\n Overload 1 of 2, \'(timeout: string | number | Timeout | undefined): void\', gave the following error.\\n Argument of type \'Timeout | null\' is not assignable to parameter of type \'string | number | Timeout | undefined\'.\\n Type \'null\' is not assignable to type \'string | number | Timeout | undefined\'.\\n Overload 2 of 2, \'(id: number | undefined): void\', gave the following error.\\n Argument of type \'Timeout | null\' is not assignable to parameter of type \'number | undefined\'.\\n Type \'null\' is not assignable to type \'number | undefined\'.", "1882595422"], + [1204, 23, 22, "Object is possibly \'undefined\'.", "576852750"], + [1204, 23, 32, "Object is possibly \'undefined\'.", "525756929"], + [1244, 17, 34, "No overload matches this call.\\n Overload 1 of 2, \'(timeout: string | number | Timeout | undefined): void\', gave the following error.\\n Argument of type \'Timeout | null\' is not assignable to parameter of type \'string | number | Timeout | undefined\'.\\n Type \'null\' is not assignable to type \'string | number | Timeout | undefined\'.\\n Overload 2 of 2, \'(id: number | undefined): void\', gave the following error.\\n Argument of type \'Timeout | null\' is not assignable to parameter of type \'number | undefined\'.\\n Type \'null\' is not assignable to type \'number | undefined\'.", "4009237785"], + [1245, 17, 31, "No overload matches this call.\\n Overload 1 of 2, \'(timeout: string | number | Timeout | undefined): void\', gave the following error.\\n Argument of type \'Timeout | null\' is not assignable to parameter of type \'string | number | Timeout | undefined\'.\\n Type \'null\' is not assignable to type \'string | number | Timeout | undefined\'.\\n Overload 2 of 2, \'(id: number | undefined): void\', gave the following error.\\n Argument of type \'Timeout | null\' is not assignable to parameter of type \'number | undefined\'.\\n Type \'null\' is not assignable to type \'number | undefined\'.", "315042064"], + [1246, 17, 30, "No overload matches this call.\\n Overload 1 of 2, \'(timeout: string | number | Timeout | undefined): void\', gave the following error.\\n Argument of type \'Timeout | null\' is not assignable to parameter of type \'string | number | Timeout | undefined\'.\\n Type \'null\' is not assignable to type \'string | number | Timeout | undefined\'.\\n Overload 2 of 2, \'(id: number | undefined): void\', gave the following error.\\n Argument of type \'Timeout | null\' is not assignable to parameter of type \'number | undefined\'.\\n Type \'null\' is not assignable to type \'number | undefined\'.", "1882595422"], + [1247, 17, 25, "No overload matches this call.\\n Overload 1 of 2, \'(timeout: string | number | Timeout | undefined): void\', gave the following error.\\n Argument of type \'Timeout | null\' is not assignable to parameter of type \'string | number | Timeout | undefined\'.\\n Type \'null\' is not assignable to type \'string | number | Timeout | undefined\'.\\n Overload 2 of 2, \'(id: number | undefined): void\', gave the following error.\\n Argument of type \'Timeout | null\' is not assignable to parameter of type \'number | undefined\'.\\n Type \'null\' is not assignable to type \'number | undefined\'.", "398879383"] + ], + "src/app/widgets/widget-boolean-switch/widget-boolean-switch.component.ts:46644229": [ + [76, 38, 9, "Argument of type \'string | undefined\' is not assignable to parameter of type \'string\'.\\n Type \'undefined\' is not assignable to type \'string\'.", "4119212820"], + [99, 10, 12, "Object is possibly \'null\'.", "4261782498"] + ], + "src/app/widgets/widget-data-chart/widget-data-chart.component.ts:2822430409": [ + [80, 4, 18, "Type \'null\' is not assignable to type \'number | undefined\'.", "1866818091"], + [81, 4, 18, "Type \'null\' is not assignable to type \'number | undefined\'.", "1866818357"], + [83, 4, 9, "Type \'null\' is not assignable to type \'number | undefined\'.", "212862030"], + [84, 4, 9, "Type \'null\' is not assignable to type \'number | undefined\'.", "212862288"], + [107, 9, 3, "\'cfg\' is possibly \'undefined\'.", "193415815"], + [110, 12, 3, "\'cfg\' is possibly \'undefined\'.", "193415815"], + [110, 31, 3, "\'cfg\' is possibly \'undefined\'.", "193415815"], + [110, 50, 3, "\'cfg\' is possibly \'undefined\'.", "193415815"], + [110, 71, 3, "\'cfg\' is possibly \'undefined\'.", "193415815"], + [110, 86, 3, "\'cfg\' is possibly \'undefined\'.", "193415815"], + [110, 98, 3, "\'cfg\' is possibly \'undefined\'.", "193415815"], + [123, 33, 22, "Argument of type \'IWidgetSvcConfig | undefined\' is not assignable to parameter of type \'IWidgetSvcConfig\'.\\n Type \'undefined\' is not assignable to type \'IWidgetSvcConfig\'.", "576852750"], + [137, 10, 22, "Type \'boolean | undefined\' is not assignable to type \'boolean | null\'.\\n Type \'undefined\' is not assignable to type \'boolean | null\'.", "609774233"], + [171, 71, 10, "Argument of type \'number | undefined\' is not assignable to parameter of type \'number\'.\\n Type \'undefined\' is not assignable to type \'number\'.", "3461732844"], + [179, 6, 6, "Type \'number | undefined\' is not assignable to type \'number\'.\\n Type \'undefined\' is not assignable to type \'number\'.", "1893769376"], + [187, 27, 22, "Object is possibly \'undefined\'.", "1240567228"], + [197, 4, 21, "Object is possibly \'undefined\'.", "406043295"], + [198, 4, 21, "Object is possibly \'undefined\'.", "406043295"], + [199, 4, 21, "Object is possibly \'undefined\'.", "406043295"], + [202, 6, 21, "Object is possibly \'undefined\'.", "406043295"], + [211, 26, 18, "Object is possibly \'null\'.", "3639984181"], + [211, 55, 18, "Object is possibly \'null\'.", "3639984181"], + [216, 18, 18, "Object is possibly \'null\'.", "3639984181"], + [237, 19, 12, "Object is possibly \'null\'.", "765689629"], + [244, 10, 12, "Type \'number | null | undefined\' is not assignable to type \'number | undefined\'.\\n Type \'null\' is not assignable to type \'number | undefined\'.", "3614877034"], + [245, 10, 12, "Type \'number | null | undefined\' is not assignable to type \'number | undefined\'.\\n Type \'null\' is not assignable to type \'number | undefined\'.", "3614877300"], + [246, 10, 3, "Type \'number | null | undefined\' is not assignable to type \'number | undefined\'.\\n Type \'null\' is not assignable to type \'number | undefined\'.", "193413807"], + [247, 10, 3, "Type \'number | null | undefined\' is not assignable to type \'number | undefined\'.\\n Type \'null\' is not assignable to type \'number | undefined\'.", "193414065"], + [266, 19, 12, "Object is possibly \'null\'.", "765689629"], + [271, 6, 21, "Object is possibly \'undefined\'.", "406043295"], + [277, 26, 18, "Object is possibly \'null\'.", "3639984181"], + [277, 55, 18, "Object is possibly \'null\'.", "3639984181"], + [282, 18, 18, "Object is possibly \'null\'.", "3639984181"], + [303, 19, 12, "Object is possibly \'null\'.", "765689629"], + [309, 10, 12, "Type \'number | null | undefined\' is not assignable to type \'number | undefined\'.\\n Type \'null\' is not assignable to type \'number | undefined\'.", "3614877034"], + [310, 10, 12, "Type \'number | null | undefined\' is not assignable to type \'number | undefined\'.\\n Type \'null\' is not assignable to type \'number | undefined\'.", "3614877300"], + [311, 10, 3, "Type \'number | null | undefined\' is not assignable to type \'number | undefined\'.\\n Type \'null\' is not assignable to type \'number | undefined\'.", "193413807"], + [312, 10, 3, "Type \'number | null | undefined\' is not assignable to type \'number | undefined\'.\\n Type \'null\' is not assignable to type \'number | undefined\'.", "193414065"], + [331, 19, 12, "Object is possibly \'null\'.", "765689629"], + [336, 4, 21, "Object is possibly \'undefined\'.", "406043295"], + [365, 8, 11, "Type \'{ minimumLine: { type: \\"line\\"; scaleID: string; display: boolean | undefined; value: null; drawTime: \\"afterDatasetsDraw\\"; label: { display: true; position: \\"start\\"; yAdjust: number; padding: number; color: string; backgroundColor: string; }; }; maximumLine: { ...; }; averageLine: { ...; }; }\' is not assignable to type \'_DeepPartialObject>> | _DeepPartialArray> | undefined\'.\\n Types of property \'minimumLine\' are incompatible.\\n Type \'{ type: \\"line\\"; scaleID: string; display: boolean | undefined; value: null; drawTime: \\"afterDatasetsDraw\\"; label: { display: true; position: \\"start\\"; yAdjust: number; padding: number; color: string; backgroundColor: string; }; }\' is not assignable to type \'_DeepPartialObject<{ type: \\"label\\"; } & LabelAnnotationOptions> | _DeepPartialObject<{ type: \\"ellipse\\"; } & EllipseAnnotationOptions> | ... 4 more ... | undefined\'.\\n Types of property \'value\' are incompatible.\\n Type \'null\' is not assignable to type \'string | number | ((ctx: PartialEventContext, options: AnnotationOptions) => string | number) | undefined\'.", "2422304113"], + [418, 18, 19, "Object is possibly \'null\'.", "1734867054"], + [418, 54, 19, "Object is possibly \'null\'.", "1734867054"], + [419, 15, 19, "Object is possibly \'null\'.", "1734867054"], + [420, 19, 18, "Object is possibly \'null\'.", "3639984181"], + [420, 70, 18, "Object is possibly \'null\'.", "3639984181"], + [420, 122, 18, "Object is possibly \'null\'.", "3639984181"], + [558, 6, 9, "Type \'null\' is not assignable to type \'string\'.", "384690336"], + [559, 6, 9, "Type \'null\' is not assignable to type \'string\'.", "384749729"], + [560, 6, 11, "Type \'null\' is not assignable to type \'string\'.", "936435848"], + [561, 6, 11, "Type \'null\' is not assignable to type \'string\'.", "935954057"], + [562, 6, 16, "Type \'null\' is not assignable to type \'string\'.", "505309252"], + [563, 6, 10, "Type \'null\' is not assignable to type \'string\'.", "1290121711"], + [564, 6, 10, "Type \'null\' is not assignable to type \'string\'.", "1316340194"], + [570, 29, 12, "Object is possibly \'null\'.", "765689629"], + [571, 29, 12, "Object is possibly \'null\'.", "765689629"], + [572, 31, 12, "Object is possibly \'null\'.", "765689629"], + [573, 31, 12, "Object is possibly \'null\'.", "765689629"], + [576, 29, 12, "Object is possibly \'null\'.", "765689629"], + [577, 29, 12, "Object is possibly \'null\'.", "765689629"], + [578, 31, 12, "Object is possibly \'null\'.", "765689629"], + [579, 31, 12, "Object is possibly \'null\'.", "765689629"], + [580, 30, 12, "Object is possibly \'null\'.", "765689629"], + [582, 34, 12, "Object is possibly \'null\'.", "765689629"], + [583, 28, 12, "Object is possibly \'null\'.", "765689629"], + [588, 29, 12, "Object is possibly \'null\'.", "765689629"], + [589, 29, 12, "Object is possibly \'null\'.", "765689629"], + [590, 31, 12, "Object is possibly \'null\'.", "765689629"], + [591, 31, 12, "Object is possibly \'null\'.", "765689629"], + [594, 29, 12, "Object is possibly \'null\'.", "765689629"], + [595, 29, 12, "Object is possibly \'null\'.", "765689629"], + [596, 31, 12, "Object is possibly \'null\'.", "765689629"], + [597, 31, 12, "Object is possibly \'null\'.", "765689629"], + [600, 34, 12, "Object is possibly \'null\'.", "765689629"], + [601, 28, 12, "Object is possibly \'null\'.", "765689629"], + [606, 29, 12, "Object is possibly \'null\'.", "765689629"], + [607, 29, 12, "Object is possibly \'null\'.", "765689629"], + [608, 31, 12, "Object is possibly \'null\'.", "765689629"], + [609, 31, 12, "Object is possibly \'null\'.", "765689629"], + [612, 29, 12, "Object is possibly \'null\'.", "765689629"], + [613, 29, 12, "Object is possibly \'null\'.", "765689629"], + [614, 31, 12, "Object is possibly \'null\'.", "765689629"], + [615, 31, 12, "Object is possibly \'null\'.", "765689629"], + [618, 34, 12, "Object is possibly \'null\'.", "765689629"], + [619, 28, 12, "Object is possibly \'null\'.", "765689629"], + [624, 29, 12, "Object is possibly \'null\'.", "765689629"], + [625, 29, 12, "Object is possibly \'null\'.", "765689629"], + [626, 31, 12, "Object is possibly \'null\'.", "765689629"], + [627, 31, 12, "Object is possibly \'null\'.", "765689629"], + [630, 29, 12, "Object is possibly \'null\'.", "765689629"], + [631, 29, 12, "Object is possibly \'null\'.", "765689629"], + [632, 31, 12, "Object is possibly \'null\'.", "765689629"], + [633, 31, 12, "Object is possibly \'null\'.", "765689629"], + [636, 34, 12, "Object is possibly \'null\'.", "765689629"], + [637, 28, 12, "Object is possibly \'null\'.", "765689629"], + [642, 29, 12, "Object is possibly \'null\'.", "765689629"], + [643, 29, 12, "Object is possibly \'null\'.", "765689629"], + [644, 31, 12, "Object is possibly \'null\'.", "765689629"], + [645, 31, 12, "Object is possibly \'null\'.", "765689629"], + [648, 29, 12, "Object is possibly \'null\'.", "765689629"], + [649, 29, 12, "Object is possibly \'null\'.", "765689629"], + [650, 31, 12, "Object is possibly \'null\'.", "765689629"], + [651, 31, 12, "Object is possibly \'null\'.", "765689629"], + [654, 34, 12, "Object is possibly \'null\'.", "765689629"], + [655, 28, 12, "Object is possibly \'null\'.", "765689629"], + [660, 29, 12, "Object is possibly \'null\'.", "765689629"], + [661, 29, 12, "Object is possibly \'null\'.", "765689629"], + [662, 31, 12, "Object is possibly \'null\'.", "765689629"], + [663, 31, 12, "Object is possibly \'null\'.", "765689629"], + [666, 29, 12, "Object is possibly \'null\'.", "765689629"], + [667, 29, 12, "Object is possibly \'null\'.", "765689629"], + [668, 31, 12, "Object is possibly \'null\'.", "765689629"], + [669, 31, 12, "Object is possibly \'null\'.", "765689629"], + [672, 34, 12, "Object is possibly \'null\'.", "765689629"], + [673, 28, 12, "Object is possibly \'null\'.", "765689629"], + [678, 29, 12, "Object is possibly \'null\'.", "765689629"], + [679, 29, 12, "Object is possibly \'null\'.", "765689629"], + [680, 31, 12, "Object is possibly \'null\'.", "765689629"], + [681, 31, 12, "Object is possibly \'null\'.", "765689629"], + [684, 29, 12, "Object is possibly \'null\'.", "765689629"], + [685, 29, 12, "Object is possibly \'null\'.", "765689629"], + [686, 31, 12, "Object is possibly \'null\'.", "765689629"], + [687, 31, 12, "Object is possibly \'null\'.", "765689629"], + [690, 34, 12, "Object is possibly \'null\'.", "765689629"], + [691, 28, 12, "Object is possibly \'null\'.", "765689629"], + [696, 29, 12, "Object is possibly \'null\'.", "765689629"], + [697, 29, 12, "Object is possibly \'null\'.", "765689629"], + [698, 31, 12, "Object is possibly \'null\'.", "765689629"], + [699, 31, 12, "Object is possibly \'null\'.", "765689629"], + [702, 29, 12, "Object is possibly \'null\'.", "765689629"], + [703, 29, 12, "Object is possibly \'null\'.", "765689629"], + [704, 31, 12, "Object is possibly \'null\'.", "765689629"], + [705, 31, 12, "Object is possibly \'null\'.", "765689629"], + [708, 34, 12, "Object is possibly \'null\'.", "765689629"], + [709, 28, 12, "Object is possibly \'null\'.", "765689629"], + [716, 8, 5, "Type \'null\' is not assignable to type \'string\'.", "173467459"], + [742, 8, 5, "Type \'string | null | undefined\' is not assignable to type \'string\'.\\n Type \'undefined\' is not assignable to type \'string\'.", "173467459"], + [761, 66, 10, "Argument of type \'number | undefined\' is not assignable to parameter of type \'number\'.\\n Type \'undefined\' is not assignable to type \'number\'.", "3461732844"], + [762, 18, 4, "\'info\' is possibly \'null\'.", "2087826411"], + [763, 21, 4, "\'info\' is possibly \'null\'.", "2087826411"], + [764, 23, 4, "\'info\' is possibly \'null\'.", "2087826411"], + [804, 59, 17, "Argument of type \'string | null | undefined\' is not assignable to parameter of type \'string\'.\\n Type \'undefined\' is not assignable to type \'string\'.", "1101890339"], + [806, 6, 26, "Object is possibly \'undefined\'.", "3315132651"], + [806, 6, 32, "Object is possibly \'undefined\'.", "1289477637"], + [806, 49, 14, "\'convertedTrack\' is possibly \'null\'.", "2974017500"], + [809, 56, 17, "Argument of type \'string | null | undefined\' is not assignable to parameter of type \'string\'.\\n Type \'undefined\' is not assignable to type \'string\'.", "1101890339"], + [810, 56, 17, "Argument of type \'string | null | undefined\' is not assignable to parameter of type \'string\'.\\n Type \'undefined\' is not assignable to type \'string\'.", "1101890339"], + [811, 56, 17, "Argument of type \'string | null | undefined\' is not assignable to parameter of type \'string\'.\\n Type \'undefined\' is not assignable to type \'string\'.", "1101890339"], + [818, 6, 21, "Type \'number | null\' is not assignable to type \'number | undefined\'.\\n Type \'null\' is not assignable to type \'number | undefined\'.", "869002562"], + [819, 6, 21, "\'ann.averageLine.label\' is possibly \'undefined\'.", "833584207"], + [819, 41, 11, "\'lastAverage\' is possibly \'null\'.", "3212571500"], + [823, 6, 21, "Type \'number | null\' is not assignable to type \'number | undefined\'.\\n Type \'null\' is not assignable to type \'number | undefined\'.", "3047629975"], + [824, 6, 21, "\'ann.minimumLine.label\' is possibly \'undefined\'.", "3059351706"], + [824, 41, 11, "\'lastMinimum\' is possibly \'null\'.", "622014457"], + [828, 6, 21, "Type \'number | null\' is not assignable to type \'number | undefined\'.\\n Type \'null\' is not assignable to type \'number | undefined\'.", "1387076873"], + [829, 6, 21, "\'ann.maximumLine.label\' is possibly \'undefined\'.", "1375355140"], + [829, 41, 11, "\'lastMaximum\' is possibly \'null\'.", "348562919"], + [835, 67, 3, "\'cfg\' is possibly \'undefined\'.", "193415815"], + [835, 67, 17, "Argument of type \'string | null | undefined\' is not assignable to parameter of type \'string\'.\\n Type \'undefined\' is not assignable to type \'string\'.", "1101890339"], + [836, 26, 3, "\'cfg\' is possibly \'undefined\'.", "193415815"], + [837, 19, 3, "\'cfg\' is possibly \'undefined\'.", "193415815"], + [839, 4, 6, "Type \'({ x: number | null; y: number; } | { x: number; y: number | null; })[]\' is not assignable to type \'IDataSetRow[]\'.\\n Type \'{ x: number | null; y: number; } | { x: number; y: number | null; }\' is not assignable to type \'IDataSetRow\'.\\n Type \'{ x: number | null; y: number; }\' is not assignable to type \'IDataSetRow\'.\\n Types of property \'x\' are incompatible.\\n Type \'number | null\' is not assignable to type \'number\'.\\n Type \'null\' is not assignable to type \'number\'.", "2123913871"], + [850, 37, 6, "Type \'undefined\' cannot be used as an index type.", "1320645186"], + [862, 55, 6, "Type \'undefined\' cannot be used as an index type.", "1320645186"] + ], + "src/app/widgets/widget-datetime/widget-datetime.component.ts:3033260432": [ + [60, 40, 9, "Argument of type \'undefined\' is not assignable to parameter of type \'string\'.", "2620553983"], + [61, 10, 10, "Type \'undefined\' is not assignable to type \'string\'.", "4110290259"], + [78, 46, 19, "Argument of type \'string | undefined\' is not assignable to parameter of type \'string\'.\\n Type \'undefined\' is not assignable to type \'string\'.", "3336110771"], + [101, 4, 14, "Type \'CanvasRenderingContext2D | null\' is not assignable to type \'CanvasRenderingContext2D\'.\\n Type \'null\' is not assignable to type \'CanvasRenderingContext2D\'.", "912271434"], + [141, 34, 9, "Argument of type \'string | undefined\' is not assignable to parameter of type \'string\'.\\n Type \'undefined\' is not assignable to type \'string\'.", "4119212820"], + [142, 32, 9, "Argument of type \'string | undefined\' is not assignable to parameter of type \'string\'.\\n Type \'undefined\' is not assignable to type \'string\'.", "4119212820"], + [164, 56, 22, "Object is possibly \'undefined\'.", "576852750"], + [168, 8, 18, "Argument of type \'string | undefined\' is not assignable to parameter of type \'string\'.\\n Type \'undefined\' is not assignable to type \'string\'.", "1687642929"], + [174, 54, 22, "Object is possibly \'undefined\'.", "576852750"], + [194, 36, 17, "Argument of type \'string | undefined\' is not assignable to parameter of type \'string\'.\\n Type \'undefined\' is not assignable to type \'string\'.", "1983154939"] + ], + "src/app/widgets/widget-freeboardsk/widget-freeboardsk.component.ts:3637980361": [ + [44, 9, 9, "Type \'null\' is not assignable to type \'string\'.", "2966443234"], + [148, 40, 27, "Object is possibly \'undefined\'.", "3506675417"] + ], + "src/app/widgets/widget-gauge-ng-compass/widget-gauge-ng-compass.component.ts:1976286112": [ + [235, 30, 9, "Argument of type \'string | undefined\' is not assignable to parameter of type \'string\'.\\n Type \'undefined\' is not assignable to type \'string\'.", "4119212820"] + ], + "src/app/widgets/widget-gauge-ng-linear/widget-gauge-ng-linear.component.ts:1738357127": [ + [93, 43, 7, "Argument of type \'() => IScale | { min: number | undefined; max: number | undefined; majorTicks: never[]; }\' is not assignable to parameter of type \'() => IScale\'.\\n Type \'IScale | { min: number | undefined; max: number | undefined; majorTicks: never[]; }\' is not assignable to type \'IScale\'.\\n Type \'{ min: number | undefined; max: number | undefined; majorTicks: never[]; }\' is not assignable to type \'IScale\'.\\n Types of property \'min\' are incompatible.\\n Type \'number | undefined\' is not assignable to type \'number\'.\\n Type \'undefined\' is not assignable to type \'number\'.", "1860344028"], + [97, 44, 16, "\'cfg.displayScale\' is possibly \'undefined\'.", "2211049739"], + [97, 44, 22, "Argument of type \'number | undefined\' is not assignable to parameter of type \'number\'.\\n Type \'undefined\' is not assignable to type \'number\'.", "4184355206"], + [97, 68, 16, "\'cfg.displayScale\' is possibly \'undefined\'.", "2211049739"], + [99, 18, 16, "\'cfg.displayScale\' is possibly \'undefined\'.", "2211049739"], + [99, 47, 16, "\'cfg.displayScale\' is possibly \'undefined\'.", "2211049739"], + [126, 25, 16, "\'cfg.displayScale\' is possibly \'undefined\'.", "2211049739"], + [129, 49, 16, "\'cfg.displayScale\' is possibly \'undefined\'.", "2211049739"], + [129, 49, 22, "Argument of type \'number | undefined\' is not assignable to parameter of type \'number\'.\\n Type \'undefined\' is not assignable to type \'number\'.", "4184355206"], + [129, 74, 16, "\'cfg.displayScale\' is possibly \'undefined\'.", "2211049739"], + [129, 74, 22, "Argument of type \'number | undefined\' is not assignable to parameter of type \'number\'.\\n Type \'undefined\' is not assignable to type \'number\'.", "4194286055"], + [157, 78, 22, "Object is possibly \'undefined\'.", "576852750"], + [170, 31, 22, "Argument of type \'IWidgetSvcConfig | undefined\' is not assignable to parameter of type \'IWidgetSvcConfig\'.\\n Type \'undefined\' is not assignable to type \'IWidgetSvcConfig\'.", "576852750"], + [201, 12, 3, "\'cfg\' is possibly \'undefined\'.", "193415815"], + [204, 29, 3, "\'cfg\' is possibly \'undefined\'.", "193415815"], + [205, 34, 3, "\'cfg\' is possibly \'undefined\'.", "193415815"], + [205, 34, 9, "Argument of type \'string | undefined\' is not assignable to parameter of type \'string\'.\\n Type \'undefined\' is not assignable to type \'string\'.", "4119212820"], + [209, 32, 5, "\'theme\' is possibly \'null\'.", "183206964"], + [210, 35, 5, "\'theme\' is possibly \'null\'.", "183206964"], + [212, 37, 5, "\'theme\' is possibly \'null\'.", "183206964"], + [213, 35, 5, "\'theme\' is possibly \'null\'.", "183206964"], + [218, 32, 5, "\'theme\' is possibly \'null\'.", "183206964"], + [219, 35, 5, "\'theme\' is possibly \'null\'.", "183206964"], + [221, 37, 5, "\'theme\' is possibly \'null\'.", "183206964"], + [222, 35, 5, "\'theme\' is possibly \'null\'.", "183206964"], + [227, 32, 5, "\'theme\' is possibly \'null\'.", "183206964"], + [228, 35, 5, "\'theme\' is possibly \'null\'.", "183206964"], + [230, 37, 5, "\'theme\' is possibly \'null\'.", "183206964"], + [231, 35, 5, "\'theme\' is possibly \'null\'.", "183206964"], + [277, 30, 9, "Argument of type \'string | undefined\' is not assignable to parameter of type \'string\'.\\n Type \'undefined\' is not assignable to type \'string\'.", "4119212820"] + ], + "src/app/widgets/widget-gauge-ng-radial/widget-gauge-ng-radial.component.ts:1445903677": [ + [176, 78, 22, "Object is possibly \'undefined\'.", "576852750"], + [189, 31, 22, "Argument of type \'IWidgetSvcConfig | undefined\' is not assignable to parameter of type \'IWidgetSvcConfig\'.\\n Type \'undefined\' is not assignable to type \'IWidgetSvcConfig\'.", "576852750"], + [219, 12, 3, "\'cfg\' is possibly \'undefined\'.", "193415815"], + [224, 39, 5, "\'theme\' is possibly \'null\'.", "183206964"], + [225, 38, 5, "\'theme\' is possibly \'null\'.", "183206964"], + [226, 36, 5, "\'theme\' is possibly \'null\'.", "183206964"], + [229, 39, 5, "\'theme\' is possibly \'null\'.", "183206964"], + [230, 38, 5, "\'theme\' is possibly \'null\'.", "183206964"], + [231, 36, 5, "\'theme\' is possibly \'null\'.", "183206964"], + [234, 39, 5, "\'theme\' is possibly \'null\'.", "183206964"], + [235, 38, 5, "\'theme\' is possibly \'null\'.", "183206964"], + [236, 36, 5, "\'theme\' is possibly \'null\'.", "183206964"], + [239, 39, 5, "\'theme\' is possibly \'null\'.", "183206964"], + [240, 38, 3, "\'cfg\' is possibly \'undefined\'.", "193415815"], + [240, 85, 3, "\'cfg\' is possibly \'undefined\'.", "193415815"], + [240, 85, 9, "Argument of type \'string | undefined\' is not assignable to parameter of type \'string\'.\\n Type \'undefined\' is not assignable to type \'string\'.", "4119212820"], + [240, 121, 3, "\'cfg\' is possibly \'undefined\'.", "193415815"], + [240, 121, 9, "Argument of type \'string | undefined\' is not assignable to parameter of type \'string\'.\\n Type \'undefined\' is not assignable to type \'string\'.", "4119212820"], + [241, 46, 3, "\'cfg\' is possibly \'undefined\'.", "193415815"], + [241, 46, 9, "Argument of type \'string | undefined\' is not assignable to parameter of type \'string\'.\\n Type \'undefined\' is not assignable to type \'string\'.", "4119212820"], + [308, 81, 9, "Argument of type \'string | undefined\' is not assignable to parameter of type \'string\'.\\n Type \'undefined\' is not assignable to type \'string\'.", "4119212820"], + [309, 30, 9, "Argument of type \'string | undefined\' is not assignable to parameter of type \'string\'.\\n Type \'undefined\' is not assignable to type \'string\'.", "4119212820"], + [309, 84, 9, "Argument of type \'string | undefined\' is not assignable to parameter of type \'string\'.\\n Type \'undefined\' is not assignable to type \'string\'.", "4119212820"], + [313, 101, 9, "Argument of type \'string | undefined\' is not assignable to parameter of type \'string\'.\\n Type \'undefined\' is not assignable to type \'string\'.", "4119212820"], + [323, 54, 9, "Argument of type \'string | undefined\' is not assignable to parameter of type \'string\'.\\n Type \'undefined\' is not assignable to type \'string\'.", "4119212820"], + [331, 17, 9, "\'cfg.gauge\' is possibly \'undefined\'.", "4124321432"], + [333, 10, 9, "\'cfg.gauge\' is possibly \'undefined\'.", "4124321432"] + ], + "src/app/widgets/widget-iframe/widget-iframe.component.ts:2602616758": [ + [30, 4, 9, "Type \'null\' is not assignable to type \'string | undefined\'.", "2966443234"] + ], + "src/app/widgets/widget-label/widget-label.component.ts:3172675525": [ + [53, 39, 9, "Argument of type \'string | undefined\' is not assignable to parameter of type \'string\'.\\n Type \'undefined\' is not assignable to type \'string\'.", "4119212820"] + ], + "src/app/widgets/widget-multi-state-switch/widget-multi-state-switch.component.ts:3679063603": [ + [50, 4, 5, "Type \'{ controlPath: { description: string; path: null; source: null; pathType: \\"multiple\\"; supportsPut: true; isPathConfigurable: true; pathRequired: true; showPathSkUnitsFilter: false; pathSkUnitsFilter: null; showConvertUnitTo: false; convertUnitTo: null; sampleTime: number; }; }\' is not assignable to type \'IPathArray | IWidgetPath[] | undefined\'.\\n The types of \'controlPath.convertUnitTo\' are incompatible between these types.\\n Type \'null\' is not assignable to type \'string | undefined\'.", "187670523"], + [160, 22, 10, "Object is possibly \'undefined\'.", "3996575854"] + ], + "src/app/widgets/widget-numeric/widget-numeric.component.ts:1149234437": [ + [62, 40, 9, "Argument of type \'undefined\' is not assignable to parameter of type \'string\'.", "2620553983"], + [70, 10, 9, "Type \'null\' is not assignable to type \'number\'.", "834508926"], + [71, 10, 8, "Type \'null\' is not assignable to type \'number\'.", "955872026"], + [72, 10, 8, "Type \'null\' is not assignable to type \'number\'.", "3919488324"], + [73, 10, 10, "Type \'undefined\' is not assignable to type \'string\'.", "4110290259"], + [74, 10, 15, "Type \'undefined\' is not assignable to type \'string\'.", "117091620"], + [107, 9, 23, "Object is possibly \'undefined\'.", "924630673"], + [112, 35, 12, "Object is possibly \'null\'.", "765689629"], + [115, 35, 12, "Object is possibly \'null\'.", "765689629"], + [118, 35, 12, "Object is possibly \'null\'.", "765689629"], + [130, 27, 22, "Object is possibly \'undefined\'.", "576852750"], + [130, 27, 36, "Argument of type \'boolean | undefined\' is not assignable to parameter of type \'boolean\'.\\n Type \'undefined\' is not assignable to type \'boolean\'.", "302325484"], + [154, 8, 13, "Type \'null\' is not assignable to type \'number\'.", "2207342764"], + [155, 8, 13, "Type \'null\' is not assignable to type \'number\'.", "1610969202"], + [156, 8, 14, "Type \'null\' is not assignable to type \'number\'.", "261643286"], + [189, 6, 16, "Object is possibly \'undefined\'.", "1024658627"], + [196, 4, 14, "Type \'CanvasRenderingContext2D | null\' is not assignable to type \'CanvasRenderingContext2D\'.\\n Type \'null\' is not assignable to type \'CanvasRenderingContext2D\'.", "912271434"], + [228, 29, 22, "Object is possibly \'undefined\'.", "576852750"], + [233, 21, 3, "\'cfg\' is possibly \'undefined\'.", "193415815"], + [233, 21, 9, "\'cfg.paths\' is possibly \'undefined\'.", "4139429943"], + [234, 4, 16, "Object is possibly \'undefined\'.", "1024658627"], + [235, 4, 16, "Object is possibly \'undefined\'.", "1024658627"], + [236, 4, 16, "Object is possibly \'undefined\'.", "1024658627"], + [236, 4, 22, "Type \'string | undefined\' is not assignable to type \'string\'.\\n Type \'undefined\' is not assignable to type \'string\'.", "2885375952"], + [236, 29, 3, "\'cfg\' is possibly \'undefined\'.", "193415815"], + [237, 4, 16, "Object is possibly \'undefined\'.", "1024658627"], + [238, 4, 16, "Object is possibly \'undefined\'.", "1024658627"], + [238, 4, 27, "Type \'number | undefined\' is not assignable to type \'number\'.\\n Type \'undefined\' is not assignable to type \'number\'.", "301849712"], + [238, 34, 3, "\'cfg\' is possibly \'undefined\'.", "193415815"], + [239, 4, 16, "Object is possibly \'undefined\'.", "1024658627"], + [239, 4, 26, "Type \'number | undefined\' is not assignable to type \'number\'.\\n Type \'undefined\' is not assignable to type \'number\'.", "1509249862"], + [239, 33, 3, "\'cfg\' is possibly \'undefined\'.", "193415815"], + [240, 4, 16, "Object is possibly \'undefined\'.", "1024658627"], + [240, 4, 26, "Type \'number | undefined\' is not assignable to type \'number\'.\\n Type \'undefined\' is not assignable to type \'number\'.", "1509249624"], + [240, 33, 3, "\'cfg\' is possibly \'undefined\'.", "193415815"], + [241, 4, 16, "Object is possibly \'undefined\'.", "1024658627"], + [241, 4, 29, "Type \'boolean | undefined\' is not assignable to type \'boolean\'.\\n Type \'undefined\' is not assignable to type \'boolean\'.", "763700999"], + [241, 36, 3, "\'cfg\' is possibly \'undefined\'.", "193415815"], + [242, 4, 16, "Object is possibly \'undefined\'.", "1024658627"], + [242, 4, 30, "Type \'boolean | undefined\' is not assignable to type \'null\'.\\n Type \'undefined\' is not assignable to type \'null\'.", "1638858803"], + [242, 37, 3, "\'cfg\' is possibly \'undefined\'.", "193415815"], + [248, 34, 9, "Argument of type \'string | undefined\' is not assignable to parameter of type \'string\'.\\n Type \'undefined\' is not assignable to type \'string\'.", "4119212820"], + [249, 55, 9, "Argument of type \'string | undefined\' is not assignable to parameter of type \'string\'.\\n Type \'undefined\' is not assignable to type \'string\'.", "4119212820"], + [258, 17, 9, "\'cfg.paths\' is possibly \'undefined\'.", "4139429943"], + [274, 12, 15, "Argument of type \'string | undefined\' is not assignable to parameter of type \'string\'.\\n Type \'undefined\' is not assignable to type \'string\'.", "4102914388"], + [327, 18, 22, "Object is possibly \'undefined\'.", "576852750"], + [327, 18, 28, "Object is possibly \'undefined\'.", "3500113022"], + [331, 56, 22, "Object is possibly \'undefined\'.", "576852750"], + [336, 9, 3, "\'cfg\' is possibly \'undefined\'.", "193415815"], + [336, 25, 3, "\'cfg\' is possibly \'undefined\'.", "193415815"], + [338, 8, 3, "\'cfg\' is possibly \'undefined\'.", "193415815"], + [339, 95, 3, "\'cfg\' is possibly \'undefined\'.", "193415815"], + [341, 8, 3, "\'cfg\' is possibly \'undefined\'.", "193415815"], + [342, 96, 3, "\'cfg\' is possibly \'undefined\'.", "193415815"], + [362, 12, 22, "Object is possibly \'undefined\'.", "576852750"], + [362, 12, 28, "Object is possibly \'undefined\'.", "3500113022"] + ], + "src/app/widgets/widget-position/widget-position.component.ts:1704530161": [ + [91, 34, 9, "Argument of type \'string | undefined\' is not assignable to parameter of type \'string\'.\\n Type \'undefined\' is not assignable to type \'string\'.", "4119212820"] + ], + "src/app/widgets/widget-race-timer/widget-race-timer.component.ts:602896548": [ + [66, 25, 9, "Argument of type \'string | undefined\' is not assignable to parameter of type \'string\'.\\n Type \'undefined\' is not assignable to type \'string\'.", "4119212820"] + ], + "src/app/widgets/widget-racer-line/widget-racer-line.component.ts:1502528665": [ + [61, 4, 5, "Type \'{ dtsPath: { description: string; path: string; source: string; pathType: \\"number\\"; pathRequired: false; isPathConfigurable: false; convertUnitTo: string; showPathSkUnitsFilter: true; pathSkUnitsFilter: \\"m\\"; sampleTime: number; }; ... 5 more ...; ttbPath: { ...; }; }\' is not assignable to type \'IPathArray | IWidgetPath[] | undefined\'.\\n The types of \'startLineNamePath.convertUnitTo\' are incompatible between these types.\\n Type \'null\' is not assignable to type \'string | undefined\'.", "187670523"], + [174, 10, 13, "Type \'null\' is not assignable to type \'string\'.", "363509612"], + [187, 34, 9, "Argument of type \'string | undefined\' is not assignable to parameter of type \'string\'.\\n Type \'undefined\' is not assignable to type \'string\'.", "4119212820"], + [338, 4, 6, "Type \'string | null\' is not assignable to type \'string\'.\\n Type \'null\' is not assignable to type \'string\'.", "2123913871"], + [342, 4, 6, "Type \'string | null\' is not assignable to type \'string\'.\\n Type \'null\' is not assignable to type \'string\'.", "2123913871"], + [486, 25, 13, "Argument of type \'number | null\' is not assignable to parameter of type \'number\'.\\n Type \'null\' is not assignable to type \'number\'.", "2241094794"], + [490, 25, 13, "Argument of type \'number | null\' is not assignable to parameter of type \'number\'.\\n Type \'null\' is not assignable to type \'number\'.", "2926687684"] + ], + "src/app/widgets/widget-racer-timer/widget-racer-timer.component.ts:3969781521": [ + [96, 34, 9, "Argument of type \'string | undefined\' is not assignable to parameter of type \'string\'.\\n Type \'undefined\' is not assignable to type \'string\'.", "4119212820"], + [117, 12, 17, "\'cfg.nextDashboard\' is possibly \'undefined\'.", "3067379786"], + [268, 25, 13, "Argument of type \'number | null\' is not assignable to parameter of type \'number\'.\\n Type \'null\' is not assignable to type \'number\'.", "3328439093"] + ], + "src/app/widgets/widget-racesteer/widget-racesteer.component.ts:595381304": [ + [175, 55, 27, "Argument of type \'number | undefined\' is not assignable to parameter of type \'number\'.\\n Type \'undefined\' is not assignable to type \'number\'.", "1820305006"], + [215, 29, 1, "Argument of type \'number | null\' is not assignable to parameter of type \'number\'.\\n Type \'null\' is not assignable to type \'number\'.", "177619"], + [336, 100, 27, "Argument of type \'number | undefined\' is not assignable to parameter of type \'number\'.\\n Type \'undefined\' is not assignable to type \'number\'.", "1820305006"] + ], + "src/app/widgets/widget-simple-linear/widget-simple-linear.component.ts:1973487785": [ + [60, 48, 4, "Argument of type \'null\' is not assignable to parameter of type \'number\'.", "2087897566"], + [74, 17, 9, "\'cfg.paths\' is possibly \'undefined\'.", "4139429943"], + [75, 16, 16, "\'cfg.displayScale\' is possibly \'undefined\'.", "2211049739"], + [76, 16, 16, "\'cfg.displayScale\' is possibly \'undefined\'.", "2211049739"], + [77, 64, 3, "Argument of type \'number | undefined\' is not assignable to parameter of type \'number\'.\\n Type \'undefined\' is not assignable to type \'number\'.", "193413807"], + [94, 31, 16, "\'cfg.displayScale\' is possibly \'undefined\'.", "2211049739"], + [94, 31, 22, "Argument of type \'number | undefined\' is not assignable to parameter of type \'number\'.\\n Type \'undefined\' is not assignable to type \'number\'.", "4184355206"], + [97, 51, 16, "\'cfg.displayScale\' is possibly \'undefined\'.", "2211049739"], + [97, 51, 22, "Argument of type \'number | undefined\' is not assignable to parameter of type \'number\'.\\n Type \'undefined\' is not assignable to type \'number\'.", "4184355206"], + [97, 76, 16, "\'cfg.displayScale\' is possibly \'undefined\'.", "2211049739"], + [97, 76, 22, "Argument of type \'number | undefined\' is not assignable to parameter of type \'number\'.\\n Type \'undefined\' is not assignable to type \'number\'.", "4194286055"], + [111, 53, 9, "Argument of type \'string | undefined\' is not assignable to parameter of type \'string\'.\\n Type \'undefined\' is not assignable to type \'string\'.", "4119212820"], + [118, 21, 9, "\'cfg.paths\' is possibly \'undefined\'.", "4139429943"], + [119, 28, 9, "\'cfg.gauge\' is possibly \'undefined\'.", "4124321432"], + [130, 34, 9, "Argument of type \'string | undefined\' is not assignable to parameter of type \'string\'.\\n Type \'undefined\' is not assignable to type \'string\'.", "4119212820"], + [155, 22, 13, "Object is possibly \'null\'.", "1985302592"] + ], + "src/app/widgets/widget-slider/widget-slider.component.ts:413411294": [ + [28, 4, 5, "Type \'{ gaugePath: { description: string; path: null; source: null; pathType: \\"number\\"; isPathConfigurable: true; showPathSkUnitsFilter: false; pathSkUnitsFilter: null; showConvertUnitTo: false; convertUnitTo: null; supportsPut: true; sampleTime: number; }; }\' is not assignable to type \'IPathArray | IWidgetPath[] | undefined\'.\\n The types of \'\'gaugePath\'.convertUnitTo\' are incompatible between these types.\\n Type \'null\' is not assignable to type \'string | undefined\'.", "187670523"], + [59, 40, 9, "Argument of type \'undefined\' is not assignable to parameter of type \'string\'.", "2620553983"], + [60, 38, 9, "Argument of type \'undefined\' is not assignable to parameter of type \'string\'.", "2620553983"], + [88, 23, 9, "Argument of type \'string | undefined\' is not assignable to parameter of type \'string\'.\\n Type \'undefined\' is not assignable to type \'string\'.", "4119212820"], + [102, 83, 16, "\'cfg.displayScale\' is possibly \'undefined\'.", "2211049739"], + [102, 83, 22, "Argument of type \'number | undefined\' is not assignable to parameter of type \'number\'.\\n Type \'undefined\' is not assignable to type \'number\'.", "4184355206"], + [115, 21, 9, "Argument of type \'string | undefined\' is not assignable to parameter of type \'string\'.\\n Type \'undefined\' is not assignable to type \'string\'.", "4119212820"], + [124, 41, 16, "\'cfg.displayScale\' is possibly \'undefined\'.", "2211049739"], + [124, 41, 22, "Argument of type \'number | undefined\' is not assignable to parameter of type \'number\'.\\n Type \'undefined\' is not assignable to type \'number\'.", "4184355206"], + [125, 19, 16, "\'cfg.displayScale\' is possibly \'undefined\'.", "2211049739"], + [126, 48, 16, "\'cfg.displayScale\' is possibly \'undefined\'.", "2211049739"], + [126, 48, 22, "Argument of type \'number | undefined\' is not assignable to parameter of type \'number\'.\\n Type \'undefined\' is not assignable to type \'number\'.", "4194286055"], + [127, 19, 16, "\'cfg.displayScale\' is possibly \'undefined\'.", "2211049739"], + [142, 23, 16, "\'cfg.displayScale\' is possibly \'undefined\'.", "2211049739"], + [142, 23, 22, "\'cfg.displayScale.upper\' is possibly \'undefined\'.", "4194286055"], + [142, 48, 16, "\'cfg.displayScale\' is possibly \'undefined\'.", "2211049739"], + [142, 48, 22, "\'cfg.displayScale.lower\' is possibly \'undefined\'.", "4184355206"], + [144, 21, 16, "\'cfg.displayScale\' is possibly \'undefined\'.", "2211049739"], + [144, 21, 22, "\'cfg.displayScale.lower\' is possibly \'undefined\'.", "4184355206"], + [150, 23, 16, "\'cfg.displayScale\' is possibly \'undefined\'.", "2211049739"], + [150, 23, 22, "\'cfg.displayScale.upper\' is possibly \'undefined\'.", "4194286055"], + [150, 48, 16, "\'cfg.displayScale\' is possibly \'undefined\'.", "2211049739"], + [150, 48, 22, "\'cfg.displayScale.lower\' is possibly \'undefined\'.", "4184355206"], + [152, 69, 16, "\'cfg.displayScale\' is possibly \'undefined\'.", "2211049739"], + [152, 69, 22, "\'cfg.displayScale.lower\' is possibly \'undefined\'.", "4184355206"], + [156, 20, 16, "\'cfg.displayScale\' is possibly \'undefined\'.", "2211049739"], + [156, 20, 22, "\'cfg.displayScale.upper\' is possibly \'undefined\'.", "4194286055"], + [156, 45, 16, "\'cfg.displayScale\' is possibly \'undefined\'.", "2211049739"], + [156, 45, 22, "\'cfg.displayScale.lower\' is possibly \'undefined\'.", "4184355206"], + [218, 10, 14, "Type \'number | undefined\' is not assignable to type \'number\'.\\n Type \'undefined\' is not assignable to type \'number\'.", "425845355"], + [218, 27, 16, "\'cfg.displayScale\' is possibly \'undefined\'.", "2211049739"], + [220, 10, 14, "Type \'number | undefined\' is not assignable to type \'number\'.\\n Type \'undefined\' is not assignable to type \'number\'.", "425845355"], + [220, 27, 16, "\'cfg.displayScale\' is possibly \'undefined\'.", "2211049739"], + [251, 24, 6, "\'colors\' is possibly \'undefined\'.", "1544348075"], + [252, 22, 6, "\'colors\' is possibly \'undefined\'.", "1544348075"] + ], + "src/app/widgets/widget-text/widget-text.component.ts:2471009854": [ + [51, 40, 9, "Argument of type \'undefined\' is not assignable to parameter of type \'string\'.", "2620553983"], + [52, 10, 10, "Type \'undefined\' is not assignable to type \'string\'.", "4110290259"], + [87, 4, 14, "Type \'CanvasRenderingContext2D | null\' is not assignable to type \'CanvasRenderingContext2D\'.\\n Type \'null\' is not assignable to type \'CanvasRenderingContext2D\'.", "912271434"], + [122, 34, 9, "Argument of type \'string | undefined\' is not assignable to parameter of type \'string\'.\\n Type \'undefined\' is not assignable to type \'string\'.", "4119212820"], + [123, 32, 9, "Argument of type \'string | undefined\' is not assignable to parameter of type \'string\'.\\n Type \'undefined\' is not assignable to type \'string\'.", "4119212820"], + [141, 19, 3, "\'cfg\' is possibly \'undefined\'.", "193415815"], + [148, 8, 3, "\'cfg\' is possibly \'undefined\'.", "193415815"], + [148, 8, 15, "Argument of type \'string | undefined\' is not assignable to parameter of type \'string\'.\\n Type \'undefined\' is not assignable to type \'string\'.", "4102914388"], + [154, 29, 3, "\'cfg\' is possibly \'undefined\'.", "193415815"] + ], + "src/app/widgets/widget-windsteer/widget-windsteer.component.ts:608910485": [ + [205, 34, 9, "\'cfg.paths\' is possibly \'undefined\'.", "4139429943"], + [206, 35, 9, "\'cfg.paths\' is possibly \'undefined\'.", "4139429943"], + [290, 17, 10, "\'cfg.paths\' is possibly \'undefined\'.", "1351545128"], + [355, 33, 22, "Object is possibly \'undefined\'.", "576852750"], + [355, 33, 46, "Object is possibly \'undefined\'.", "1732614759"] + ], + "src/app/widgets/widget-windtrends-chart/widget-windtrends-chart.component.ts:3621756652": [ + [86, 10, 15, "Type \'null\' is not assignable to type \'Subscription\'.", "2233656204"], + [87, 10, 11, "Type \'null\' is not assignable to type \'Subscription\'.", "3429848846"], + [90, 10, 9, "Type \'null\' is not assignable to type \'TimeScaleFormat\'.", "2592770440"], + [91, 10, 14, "Type \'null\' is not assignable to type \'IChartDataSourceInfo\'.", "2985720646"], + [127, 22, 5, "\'theme\' is possibly \'null\'.", "183206964"], + [162, 26, 5, "\'theme\' is possibly \'null\'.", "183206964"], + [170, 24, 5, "\'theme\' is possibly \'null\'.", "183206964"], + [204, 28, 5, "\'theme\' is possibly \'null\'.", "183206964"], + [287, 24, 5, "\'theme\' is possibly \'null\'.", "183206964"], + [292, 26, 5, "\'theme\' is possibly \'null\'.", "183206964"], + [309, 4, 20, "Type \'Signal\' is not assignable to type \'Signal\'.\\n Type \'Signal\' is not assignable to type \'() => BreakpointState\'.\\n Type \'BreakpointState | undefined\' is not assignable to type \'BreakpointState\'.\\n Type \'undefined\' is not assignable to type \'BreakpointState\'.", "1507091964"], + [348, 29, 22, "Object is possibly \'undefined\'.", "1240567228"], + [362, 4, 21, "Object is possibly \'undefined\'.", "406043295"], + [363, 4, 21, "Object is possibly \'undefined\'.", "406043295"], + [365, 4, 21, "Object is possibly \'undefined\'.", "406043295"], + [376, 4, 21, "Object is possibly \'undefined\'.", "406043295"], + [414, 17, 12, "Object is possibly \'null\'.", "765689629"], + [457, 30, 12, "Object is possibly \'null\'.", "765689629"], + [469, 45, 12, "Object is possibly \'null\'.", "765689629"], + [514, 30, 12, "Object is possibly \'null\'.", "765689629"], + [526, 45, 12, "Object is possibly \'null\'.", "765689629"], + [533, 4, 21, "Object is possibly \'undefined\'.", "406043295"], + [595, 8, 11, "Type \'(context: ScriptableContext<\\"line\\">) => CanvasGradient | null\' is not assignable to type \'string | ((ctx: ScriptableContext<\\"line\\">, options: AnyObject) => Color | undefined) | _DeepPartialObject | _DeepPartialObject<...> | readonly (string | ... 2 more ... | undefined)[] | undefined\'.\\n Type \'(context: ScriptableContext<\\"line\\">) => CanvasGradient | null\' is not assignable to type \'(ctx: ScriptableContext<\\"line\\">, options: AnyObject) => Color | undefined\'.\\n Type \'CanvasGradient | null\' is not assignable to type \'Color | undefined\'.\\n Type \'null\' is not assignable to type \'Color | undefined\'.", "354928724"], + [764, 8, 4, "Type \'number\' is not assignable to type \'null\'.", "2088075444"], + [771, 6, 4, "Type \'number\' is not assignable to type \'null\'.", "2088075444"], + [904, 6, 25, "Object is possibly \'undefined\'.", "1481738554"], + [904, 6, 27, "Object is possibly \'undefined\'.", "3000548012"], + [905, 6, 25, "Object is possibly \'undefined\'.", "1481738554"], + [905, 6, 27, "Object is possibly \'undefined\'.", "3000548012"], + [957, 6, 25, "Object is possibly \'undefined\'.", "1481738554"], + [957, 6, 27, "Object is possibly \'undefined\'.", "3000548013"], + [958, 6, 25, "Object is possibly \'undefined\'.", "1481738554"], + [958, 6, 27, "Object is possibly \'undefined\'.", "3000548013"], + [1012, 29, 12, "Object is possibly \'null\'.", "765689629"], + [1013, 34, 12, "Object is possibly \'null\'.", "765689629"], + [1014, 34, 12, "Object is possibly \'null\'.", "765689629"], + [1015, 29, 12, "Object is possibly \'null\'.", "765689629"], + [1035, 6, 9, "Type \'null\' is not assignable to type \'string\'.", "384690336"], + [1036, 6, 9, "Type \'null\' is not assignable to type \'string\'.", "384749729"], + [1037, 6, 11, "Type \'null\' is not assignable to type \'string\'.", "936435848"], + [1038, 6, 11, "Type \'null\' is not assignable to type \'string\'.", "935954057"], + [1039, 6, 16, "Type \'null\' is not assignable to type \'string\'.", "505309252"], + [1040, 6, 10, "Type \'null\' is not assignable to type \'string\'.", "1290121711"], + [1041, 6, 10, "Type \'null\' is not assignable to type \'string\'.", "1316340194"], + [1046, 27, 12, "Object is possibly \'null\'.", "765689629"], + [1047, 27, 12, "Object is possibly \'null\'.", "765689629"], + [1048, 29, 12, "Object is possibly \'null\'.", "765689629"], + [1049, 29, 12, "Object is possibly \'null\'.", "765689629"], + [1050, 28, 12, "Object is possibly \'null\'.", "765689629"], + [1051, 34, 12, "Object is possibly \'null\'.", "765689629"], + [1052, 28, 12, "Object is possibly \'null\'.", "765689629"], + [1055, 27, 12, "Object is possibly \'null\'.", "765689629"], + [1056, 27, 12, "Object is possibly \'null\'.", "765689629"], + [1057, 29, 12, "Object is possibly \'null\'.", "765689629"], + [1058, 29, 12, "Object is possibly \'null\'.", "765689629"], + [1059, 28, 12, "Object is possibly \'null\'.", "765689629"], + [1060, 34, 12, "Object is possibly \'null\'.", "765689629"], + [1061, 28, 12, "Object is possibly \'null\'.", "765689629"], + [1064, 27, 12, "Object is possibly \'null\'.", "765689629"], + [1065, 27, 12, "Object is possibly \'null\'.", "765689629"], + [1066, 29, 12, "Object is possibly \'null\'.", "765689629"], + [1067, 29, 12, "Object is possibly \'null\'.", "765689629"], + [1068, 28, 12, "Object is possibly \'null\'.", "765689629"], + [1069, 34, 12, "Object is possibly \'null\'.", "765689629"], + [1070, 28, 12, "Object is possibly \'null\'.", "765689629"], + [1073, 27, 12, "Object is possibly \'null\'.", "765689629"], + [1074, 27, 12, "Object is possibly \'null\'.", "765689629"], + [1075, 29, 12, "Object is possibly \'null\'.", "765689629"], + [1076, 29, 12, "Object is possibly \'null\'.", "765689629"], + [1077, 28, 12, "Object is possibly \'null\'.", "765689629"], + [1078, 34, 12, "Object is possibly \'null\'.", "765689629"], + [1079, 28, 12, "Object is possibly \'null\'.", "765689629"], + [1082, 27, 12, "Object is possibly \'null\'.", "765689629"], + [1083, 27, 12, "Object is possibly \'null\'.", "765689629"], + [1084, 29, 12, "Object is possibly \'null\'.", "765689629"], + [1085, 29, 12, "Object is possibly \'null\'.", "765689629"], + [1086, 28, 12, "Object is possibly \'null\'.", "765689629"], + [1087, 34, 12, "Object is possibly \'null\'.", "765689629"], + [1088, 28, 12, "Object is possibly \'null\'.", "765689629"], + [1091, 27, 12, "Object is possibly \'null\'.", "765689629"], + [1092, 27, 12, "Object is possibly \'null\'.", "765689629"], + [1093, 29, 12, "Object is possibly \'null\'.", "765689629"], + [1094, 29, 12, "Object is possibly \'null\'.", "765689629"], + [1095, 28, 12, "Object is possibly \'null\'.", "765689629"], + [1096, 34, 12, "Object is possibly \'null\'.", "765689629"], + [1097, 28, 12, "Object is possibly \'null\'.", "765689629"], + [1100, 27, 12, "Object is possibly \'null\'.", "765689629"], + [1101, 27, 12, "Object is possibly \'null\'.", "765689629"], + [1102, 29, 12, "Object is possibly \'null\'.", "765689629"], + [1103, 29, 12, "Object is possibly \'null\'.", "765689629"], + [1104, 28, 12, "Object is possibly \'null\'.", "765689629"], + [1105, 34, 12, "Object is possibly \'null\'.", "765689629"], + [1106, 28, 12, "Object is possibly \'null\'.", "765689629"], + [1109, 27, 12, "Object is possibly \'null\'.", "765689629"], + [1110, 27, 12, "Object is possibly \'null\'.", "765689629"], + [1111, 29, 12, "Object is possibly \'null\'.", "765689629"], + [1112, 29, 12, "Object is possibly \'null\'.", "765689629"], + [1113, 28, 12, "Object is possibly \'null\'.", "765689629"], + [1114, 34, 12, "Object is possibly \'null\'.", "765689629"], + [1115, 28, 12, "Object is possibly \'null\'.", "765689629"] + ], + "src/app/widgets/widget-zones-state-panel/widget-zones-state-panel.component.ts:2501103102": [ + [78, 38, 9, "Argument of type \'string | undefined\' is not assignable to parameter of type \'string\'.\\n Type \'undefined\' is not assignable to type \'string\'.", "4119212820"] + ], + "src/default-config/config.blank.const.ts:475420683": [ + [31, 2, 12, "Type \'null\' is not assignable to type \'string\'.", "3195809883"] + ], + "src/default-config/config.blank.dashboard.ts:3810089117": [ + [4, 6, 2, "Type \'null\' is not assignable to type \'string\'.", "5861160"] + ] + }` +}; diff --git a/.betterer.ts b/.betterer.ts new file mode 100644 index 00000000..de002393 --- /dev/null +++ b/.betterer.ts @@ -0,0 +1,11 @@ +import { typescript } from '@betterer/typescript'; + +// tsconfig.strict.json is the single source of the strict compiler options. +// Betterer ignores that config's own include/exclude and uses the globs below, +// so they must mirror its file scope (all app sources, no specs, no test setup). +export default { + 'strictNullChecks': () => + typescript('./tsconfig.strict.json') + .include('./src/**/*.ts') + .exclude(/\.spec\.ts$/, /(^|\/)test\.ts$/), +}; diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index be3bb373..3e110a27 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,6 +29,27 @@ jobs: - name: Lint run: ng lint + strict-null-checks: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup Node.js 24.x + uses: actions/setup-node@v4 + with: + node-version: 24.x + cache: 'npm' + + - name: Install dependencies + run: npm install + + - name: Enforce strictNullChecks ratchet + run: npm run betterer:ci + angular-vitest: runs-on: ubuntu-latest diff --git a/.gitignore b/.gitignore index ce9804b5..96b21a1a 100644 --- a/.gitignore +++ b/.gitignore @@ -28,6 +28,7 @@ !.vscode/extensions.json # misc +/.betterer.cache /.sass-cache /connect.lock /coverage diff --git a/CLAUDE.md b/CLAUDE.md index f6bdb272..aa1a2290 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -18,6 +18,16 @@ Skip — an Angular 21 (zoneless, signals, new control flow) Signal K marine mul Node: the app builds on Node 20+. CI runs the matrix 20/22/24. +## strictNullChecks ratchet (betterer) + +`strictNullChecks` is not yet enabled in the app build — the codebase still has hundreds of latent null-safety issues, migrated file-by-file (issue #6). A [betterer](https://phenomnomnominal.github.io/betterer/) ratchet holds the line: the count can only go down. + +- `npm run snc` — `tsc -p tsconfig.strict.json`, lists your remaining `strictNullChecks` errors. `tsconfig.strict.json` is the single source of the strict compiler options and the checked file scope (all `src/**/*.ts`, no specs, no `test.ts`). +- `npm run betterer` — **regenerates** `.betterer.results` (the committed baseline). Run and commit this whenever you fix a file **or merge/rebase main into your branch**. +- `npm run betterer:ci` — the check the `strict-null-checks` CI job runs; fails on any new issue. + +The baseline is keyed by file **content hash**, so any content change to a tracked file — a real fix, or just merging main — invalidates its key and makes `betterer:ci` fail with "unexpected changes" until you regenerate. If CI reports the same count but "unexpected changes", that's the tell: run `npm run betterer` and commit the result. The check runs on Node 24; the baseline is Node-portable (Node 20/22/24 produce identical results). `tsconfig.betterer.json` is only the ts-node loader config for `.betterer.ts`, not a check config. + ## Performance and freeze measurement (perf-harness/) Self-contained freeze/jank harness (own `package.json`, never touches app deps): builds the **real production bundle**, drives it in headless Chromium at **10× CPU throttle** (Pi-class HaLOS target) against a **mock Signal K server** on one origin. Use it for perf-sensitive changes to widgets, rendering, or the data pipeline, and for before/after numbers when replicating upstream perf work. Full operator docs: `perf-harness/README.md`. diff --git a/package-lock.json b/package-lock.json index ddb89fc2..1b3e1999 100644 --- a/package-lock.json +++ b/package-lock.json @@ -31,6 +31,8 @@ "@angular/platform-browser-dynamic": "21.2.7", "@angular/router": "21.2.7", "@aziham/chartjs-plugin-streaming": "^3.5.1", + "@betterer/cli": "^5.4.0", + "@betterer/typescript": "^5.4.0", "@godind/ng-canvas-gauges": "^6.2.1", "@types/canvas-gauges": "^2.1.8", "@types/d3": "^7.4.3", @@ -3137,6 +3139,318 @@ "node": ">=18" } }, + "node_modules/@betterer/betterer": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@betterer/betterer/-/betterer-5.4.0.tgz", + "integrity": "sha512-t91JDLdUv5t70TPn1rzTiYA2WhtehDV23/KKkePMDo2Q/7QaHyHiTDG40+BnDh9LB7bW0Q4jOZXClf0tupOXNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@betterer/constraints": "^5.3.0", + "@betterer/errors": "^5.3.0", + "@betterer/logger": "^5.3.4", + "@betterer/reporter": "^5.4.0", + "@phenomnomnominal/debug": "^0.2.5", + "@phenomnomnominal/worker-require": "^0.0.34", + "chokidar": "^3.3.1", + "djb2a": "^1.2.0", + "fast-memoize": "^2.5.2", + "lines-and-columns": "^2.0.3", + "minimatch": "^5.0.1", + "prettier": "^2.3.2", + "simple-git": "^3.6.0", + "ts-node": "^10.2.1", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "typescript": ">=2.7" + } + }, + "node_modules/@betterer/betterer/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@betterer/betterer/node_modules/brace-expansion": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz", + "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@betterer/betterer/node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/@betterer/betterer/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@betterer/betterer/node_modules/lines-and-columns": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-2.0.4.tgz", + "integrity": "sha512-wM1+Z03eypVAVUCE7QdSqpVIvelbOakn1M0bPDoA4SGWPx3sNDVUiMo3L6To6WWGClB7VyXnhQ4Sn7gxiJbE6A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/@betterer/betterer/node_modules/minimatch": { + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", + "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@betterer/betterer/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@betterer/betterer/node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/@betterer/cli": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@betterer/cli/-/cli-5.4.0.tgz", + "integrity": "sha512-FtXbNLoxsg54w9LQWngXNuGNZj8BHG9qPv6r2Hvr5FYw1ZblAsTW9Vya9NlbOtSxIVrVf/aM9FVTIltTPhFHfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@betterer/betterer": "^5.4.0", + "@betterer/errors": "^5.3.0", + "@betterer/render": "^5.3.4", + "@betterer/tasks": "^5.3.6", + "@phenomnomnominal/tsquery": "^4.1.1", + "@phenomnomnominal/tstemplate": "^0.1.0", + "@phenomnomnominal/worker-require": "^0.0.34", + "chalk": "^4.1.2", + "commander": "^8.3.0", + "find-up": "^5.0.0", + "jest-diff": "^27.1.0", + "prettier": "^2.3.2", + "tslib": "^2.3.1" + }, + "bin": { + "betterer": "bin/betterer" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@betterer/cli/node_modules/@phenomnomnominal/tsquery": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@phenomnomnominal/tsquery/-/tsquery-4.2.0.tgz", + "integrity": "sha512-hR2U3uVcrrdkuG30ItQ+uFDs4ncZAybxWG0OjTE8ptPzVoU7GVeXpy+vMU8zX9EbmjGeITPw/su5HjYQyAH8bA==", + "dev": true, + "license": "MIT", + "dependencies": { + "esquery": "^1.0.1" + }, + "peerDependencies": { + "typescript": "^3 || ^4" + } + }, + "node_modules/@betterer/cli/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/@betterer/cli/node_modules/typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/@betterer/constraints": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/@betterer/constraints/-/constraints-5.3.0.tgz", + "integrity": "sha512-YmaX30/S4PoYDqGspRmUBeBE1KkLbnSQCndqPar7ZH6sWOIo29d67B7as6ODEmwpJf+GGYfmrGtTJd5c69hTng==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@betterer/errors": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/@betterer/errors/-/errors-5.3.0.tgz", + "integrity": "sha512-Z4uCvA2oSuyEHNgIgMUo+WqIP/xwy40mGmkM/cJXLWWQOTOfzELa5CNgyz4t4XNebojko2bja8n2zaXlTUzViw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/@betterer/logger": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/@betterer/logger/-/logger-5.3.4.tgz", + "integrity": "sha512-Ns4KsZ5G0F5BsBF8K0VkmAUfEGKhgog9kv8QCKuZQQNcPAX5cESIYSeEs5H4bcMDqsk0dW/sQRt/7rZWGlrFSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.10.3", + "jest-diff": "^27.0.6", + "lines-and-columns": "^2.0.3", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@betterer/logger/node_modules/lines-and-columns": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-2.0.4.tgz", + "integrity": "sha512-wM1+Z03eypVAVUCE7QdSqpVIvelbOakn1M0bPDoA4SGWPx3sNDVUiMo3L6To6WWGClB7VyXnhQ4Sn7gxiJbE6A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/@betterer/render": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/@betterer/render/-/render-5.3.4.tgz", + "integrity": "sha512-zc91zlLxWafGxG25/kUsCDmxLvQhUb4PNIq4MRU/VpnncyhdelMY5OxaIAxu9IXhJFoC6FRJhL3I7eGdND64zQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/@betterer/reporter": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@betterer/reporter/-/reporter-5.4.0.tgz", + "integrity": "sha512-+NB/zDkPv4q4oObWhvVpKghskf0K520NIm8rjfoBPAm75Y/PHWh2JSBeTSo6li25HRdvF5wZ+8tIJr1UAennmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@betterer/betterer": "^5.4.0", + "@betterer/errors": "^5.3.0", + "@betterer/logger": "^5.3.4", + "@betterer/render": "^5.3.4", + "@betterer/tasks": "^5.3.6", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@betterer/tasks": { + "version": "5.3.6", + "resolved": "https://registry.npmjs.org/@betterer/tasks/-/tasks-5.3.6.tgz", + "integrity": "sha512-UBx+My23z/q4deq5WPGNPDO/8OoK7epPpQftgaD8r1UXeD10aaV8BmjQ70Yjw/EQWDqVBBkDdbwmwspMOHjoMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@betterer/errors": "^5.3.0", + "@betterer/logger": "^5.3.4", + "@betterer/render": "^5.3.4", + "chalk": "^4.1.2", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@betterer/typescript": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@betterer/typescript/-/typescript-5.4.0.tgz", + "integrity": "sha512-wwfGRTwK1BHsqacaE6Qxii5Imy84wJBwiQoohyDWR50xSaYnU/h/4Ci6Ha3ZThgOaGrmra6ABfAGDYx7PSilkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@betterer/betterer": "^5.4.0", + "@betterer/errors": "^5.3.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "typescript": "*" + } + }, "node_modules/@braintree/sanitize-url": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-7.1.2.tgz", @@ -5137,6 +5451,23 @@ "dev": true, "license": "MIT" }, + "node_modules/@kwsites/file-exists": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@kwsites/file-exists/-/file-exists-1.1.1.tgz", + "integrity": "sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.1" + } + }, + "node_modules/@kwsites/promise-deferred": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@kwsites/promise-deferred/-/promise-deferred-1.1.1.tgz", + "integrity": "sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==", + "dev": true, + "license": "MIT" + }, "node_modules/@leichtgewicht/ip-codec": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", @@ -6543,6 +6874,45 @@ "node": ">=20.0.0" } }, + "node_modules/@phenomnomnominal/debug": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/@phenomnomnominal/debug/-/debug-0.2.5.tgz", + "integrity": "sha512-5yAKsIqcvKUiTYfsEXTt6wiNW2jWVEpa6ej8RSPSRV681av1APBK+2BpEIdOo9DAmq2bwq45Ry3zi/wxBjndaQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsite": "^1.0.0", + "esprima": "^4.0.1", + "esquery": "^1.3.1", + "tslib": "^2.0.3" + } + }, + "node_modules/@phenomnomnominal/tstemplate": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@phenomnomnominal/tstemplate/-/tstemplate-0.1.0.tgz", + "integrity": "sha512-/v+GIVNFHAz4+nQtgy9e5ZAXK3xj6TbP5s9JTpnFuqkcLB+gB2lJ6x/nsDhkKhzR6o4REuzhsYoWYnXqKC/UnQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@phenomnomnominal/worker-require": { + "version": "0.0.34", + "resolved": "https://registry.npmjs.org/@phenomnomnominal/worker-require/-/worker-require-0.0.34.tgz", + "integrity": "sha512-2GoVa1PRjrCjOpbMdzsZMQzkx/yFKqWizZc+ZNYSWE+Ym8BG+qAGDcWehUmUmGqy22wS13qitdVt6sR/DAWkIw==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsite": "^1.0.0", + "comlink": "^4.3.0", + "tslib": "^1.10.0" + } + }, + "node_modules/@phenomnomnominal/worker-require/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true, + "license": "0BSD" + }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -7551,6 +7921,23 @@ "node": "^20.17.0 || >=22.9.0" } }, + "node_modules/@simple-git/args-pathspec": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@simple-git/args-pathspec/-/args-pathspec-1.0.3.tgz", + "integrity": "sha512-ngJMaHlsWDTfjyq9F3VIQ8b7NXbBLq5j9i5bJ6XLYtD6qlDXT7fdKY2KscWWUF8t18xx052Y/PUO1K1TRc9yKA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@simple-git/argv-parser": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@simple-git/argv-parser/-/argv-parser-1.1.1.tgz", + "integrity": "sha512-Q9lBcfQ+VQCpQqGJFHe5yooOS5hGdLFFbJ5R+R5aDsnkPCahtn1hSkMcORX65J2Z5lxSkD0lQorMsncuBQxYUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@simple-git/args-pathspec": "^1.0.3" + } + }, "node_modules/@standard-schema/spec": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", @@ -9853,6 +10240,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/callsite": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", + "integrity": "sha512-0vdNRFXn5q+dtOqjfFtmtlI9N2eVZ7LMyEV2iKC5mEEFvSg/69Ml6b/WU2qF8W1nLRa0wiSrDT3Y5jOHZCwKPQ==", + "dev": true, + "engines": { + "node": "*" + } + }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -10473,6 +10869,13 @@ "dev": true, "license": "MIT" }, + "node_modules/comlink": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/comlink/-/comlink-4.4.2.tgz", + "integrity": "sha512-OxGdvBmJuNKSCMO4NTl1L47VRp6xn2wG4F/2hYzB6tiCb709otOxtEYCSvK80PtjODfXXZu8ds+Nw5kVCjqd2g==", + "dev": true, + "license": "Apache-2.0" + }, "node_modules/commander": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", @@ -11742,6 +12145,26 @@ "node": ">=0.3.1" } }, + "node_modules/diff-sequences": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz", + "integrity": "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/djb2a": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/djb2a/-/djb2a-1.2.0.tgz", + "integrity": "sha512-rXrJYOPCGvHPYw8R2u/zczFTG3xXNqklrtT17vTPm8n/4a16PKEhrfgMwJ9Zyuz96PJwZzHuK2ChQO/SSChuKA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/dns-packet": { "version": "5.6.1", "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", @@ -12721,6 +13144,13 @@ "dev": true, "license": "MIT" }, + "node_modules/fast-memoize": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/fast-memoize/-/fast-memoize-2.5.2.tgz", + "integrity": "sha512-Ue0LwpDYErFbmNnZSF0UH6eImUwDmogUO1jyE+JbN2gsQz/jICm1Ve7t9QT0rNSsfJt+Hs4/S3GnsDVjL4HVrw==", + "dev": true, + "license": "MIT" + }, "node_modules/fast-uri": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", @@ -14120,6 +14550,32 @@ "@pkgjs/parseargs": "^0.11.0" } }, + "node_modules/jest-diff": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", + "integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-get-type": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", + "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, "node_modules/jest-worker": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", @@ -17027,6 +17483,22 @@ "node": ">= 0.8.0" } }, + "node_modules/prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, "node_modules/pretty": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/pretty/-/pretty-2.0.0.tgz", @@ -17042,6 +17514,44 @@ "node": ">=0.10.0" } }, + "node_modules/pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/prismjs": { "version": "1.30.0", "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz", @@ -17299,6 +17809,13 @@ "node": ">= 0.10" } }, + "node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true, + "license": "MIT" + }, "node_modules/readable-stream": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", @@ -18323,6 +18840,24 @@ "node": "^20.17.0 || >=22.9.0" } }, + "node_modules/simple-git": { + "version": "3.36.0", + "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-3.36.0.tgz", + "integrity": "sha512-cGQjLjK8bxJw4QuYT7gxHw3/IouVESbhahSsHrX97MzCL1gu2u7oy38W6L2ZIGECEfIBG4BabsWDPjBxJENv9Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@kwsites/file-exists": "^1.1.1", + "@kwsites/promise-deferred": "^1.1.1", + "@simple-git/args-pathspec": "^1.0.3", + "@simple-git/argv-parser": "^1.1.0", + "debug": "^4.4.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/steveukx/git-js?sponsor=1" + } + }, "node_modules/sk-ais-status-plugin": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/sk-ais-status-plugin/-/sk-ais-status-plugin-1.0.0.tgz", diff --git a/package.json b/package.json index ba8e0be3..c8acd4f8 100644 --- a/package.json +++ b/package.json @@ -61,6 +61,9 @@ "test:mcp-schema": "vitest run --config tools/gen-mcp-schema/vitest.config.ts", "gen:mcp-schema": "UPDATE_SCHEMA=1 npm run test:mcp-schema", "lint": "ng lint", + "snc": "tsc -p tsconfig.strict.json", + "betterer": "betterer --tsconfig tsconfig.betterer.json", + "betterer:ci": "betterer ci --tsconfig tsconfig.betterer.json", "dev": "ng serve --configuration=dev --serve-path=/@halos-org/skip/", "build:dev": "ng build --configuration=dev", "build:prod": "ng build --configuration=production", @@ -85,6 +88,8 @@ "@angular/platform-browser-dynamic": "21.2.7", "@angular/router": "21.2.7", "@aziham/chartjs-plugin-streaming": "^3.5.1", + "@betterer/cli": "^5.4.0", + "@betterer/typescript": "^5.4.0", "@godind/ng-canvas-gauges": "^6.2.1", "@types/canvas-gauges": "^2.1.8", "@types/d3": "^7.4.3", diff --git a/src/app/core/components/data-inspector/data-inspector.component.ts b/src/app/core/components/data-inspector/data-inspector.component.ts index 6137002b..9690ea10 100644 --- a/src/app/core/components/data-inspector/data-inspector.component.ts +++ b/src/app/core/components/data-inspector/data-inspector.component.ts @@ -146,7 +146,7 @@ export class DataInspectorComponent implements AfterViewInit, OnDestroy { private toViewRow(path: ISkPathData): DataInspectorViewRow { return { path: path.path, - type: path.type, + type: path.type ?? '', supportsPut: path.meta?.supportsPut === true, sourceRows: Object.entries(path.sources ?? {}).map(([key, source]) => ({ key, diff --git a/src/app/core/interfaces/app-interfaces.ts b/src/app/core/interfaces/app-interfaces.ts index 4159d06c..79315129 100644 --- a/src/app/core/interfaces/app-interfaces.ts +++ b/src/app/core/interfaces/app-interfaces.ts @@ -17,7 +17,7 @@ import { ISkMetadata, TState } from "./signalk-interfaces"; * @memberof app-interfaces */ export interface IPathValueData { - context: string; + context: string | undefined; path: string; source: string; timestamp: string; @@ -56,8 +56,8 @@ export interface IPathUpdateEvent { path: string; // eslint-disable-next-line @typescript-eslint/no-explicit-any pathValue: any; - pathTimestamp: string; - type: string; + pathTimestamp: string | undefined; + type: string | undefined; state: TState; defaultSource?: string; // default source sources: Record(null); - private _cssThemeColorRoles: ITheme = null; + private _cssThemeColorRoles: ITheme; private readonly _settings = inject(SettingsService); private readonly _data = inject(DataService); private readonly _iconRegistry = inject(MatIconRegistry); @@ -98,9 +98,11 @@ export class AppService { }); effect(() => { - const mode = this._environmentMode().data.value; + const environmentMode = this._environmentMode(); untracked(() => { + if (!environmentMode) return; + const mode = environmentMode.data.value; if (this.previousEnvironmentMode === mode) return; // No change in mode this.previousEnvironmentMode = mode; @@ -124,8 +126,7 @@ export class AppService { }); }); - this.readThemeCssRoleVariables(); - this._cssThemeColorRoles = this.cssThemeColorRoles$.getValue(); + this._cssThemeColorRoles = this.readThemeCssRoleVariables(); this.browserVersion.set(this.getBrowserVersion()); this.osVersion.set(this.getOSVersion()); @@ -137,7 +138,7 @@ export class AppService { console.log("***********************************************"); } - private readThemeCssRoleVariables(): void { + private readThemeCssRoleVariables(): ITheme { const root = document.body; const computedStyle = getComputedStyle(root); const cssThemeRolesColor: ITheme = { @@ -176,6 +177,7 @@ export class AppService { zoneEmergency: computedStyle.getPropertyValue('--kip-zone-emergency-color').trim(), }; this.cssThemeColorRoles$.next(cssThemeRolesColor); + return cssThemeRolesColor; } public get cssThemeColors() : ITheme { @@ -220,8 +222,7 @@ export class AppService { } this.setBrightness(1, false); } - this.readThemeCssRoleVariables(); - this._cssThemeColorRoles = this.cssThemeColorRoles$.getValue(); + this._cssThemeColorRoles = this.readThemeCssRoleVariables(); } /** diff --git a/src/app/core/services/canvas.service.ts b/src/app/core/services/canvas.service.ts index a0877043..20c3de7c 100644 --- a/src/app/core/services/canvas.service.ts +++ b/src/app/core/services/canvas.service.ts @@ -72,9 +72,10 @@ export class CanvasService { // Store the callback for this canvas (if provided), wrapping to ignore zero-size if (opts.onResize) { + const onResize = opts.onResize; const filteredResize = (w: number, h: number) => { if (w === 0 || h === 0) return; - opts.onResize(w, h); + onResize(w, h); }; this.resizeCallbacks.set(canvas, filteredResize); } diff --git a/src/app/core/services/configuration-upgrade.service.spec.ts b/src/app/core/services/configuration-upgrade.service.spec.ts index c526b93e..a41b370a 100644 --- a/src/app/core/services/configuration-upgrade.service.spec.ts +++ b/src/app/core/services/configuration-upgrade.service.spec.ts @@ -27,7 +27,9 @@ describe('ConfigurationUpgradeService', () => { mockStorage.listConfigs.mockClear(); mockStorage.getConfig.mockClear(); mockStorage.setConfig.mockClear(); + mockStorage.initConfig = null; mockAppSettings.reloadApp.mockClear(); + mockAppSettings.resetSettings.mockClear(); TestBed.configureTestingModule({ providers: [ @@ -204,4 +206,44 @@ describe('ConfigurationUpgradeService', () => { expect(mockStorage.setConfig).toHaveBeenCalledWith( 'user', 'uconf', expect.objectContaining({ app: expect.objectContaining({ configVersion: 0 }) }), 9); }); + + it('legacy upgrade clears the blocking overlay when slot listing fails, without wedging', async () => { + mockStorage.listConfigs.mockRejectedValueOnce(new Error('offline')); + + await service.runUpgrade(); // legacy (version-less) path + + // The catch must reset upgrading(), matching the v11/v12 paths; leaving it set + // wedges the app behind the upgrade overlay with no dismiss. + expect(service.upgrading()).toBe(false); + }); + + it('legacy upgrade skips a slot whose config has no app section, without crashing', async () => { + mockStorage.listConfigs.mockResolvedValueOnce([{ scope: 'user', name: 'default' }]); + mockStorage.getConfig.mockResolvedValue({ theme: { themeName: '' } }); // no app section + + await service.runUpgrade(); + + // transformConfig returns null for the app-less slot, so nothing is persisted and + // the prior config.app.configVersion TypeError no longer fires. + expect(mockStorage.setConfig).not.toHaveBeenCalled(); + }); + + it('startFresh skips a legacy slot missing its app section and still retires the rest', async () => { + mockStorage.initConfig = null; // remote (Signal K) path + mockStorage.listConfigs.mockResolvedValueOnce([ + { scope: 'global', name: 'gconf' }, + { scope: 'user', name: 'uconf' } + ]); + mockStorage.getConfig.mockImplementation((scope: string, name: string) => + Promise.resolve(name === 'uconf' ? { app: { configVersion: 10 } } : { theme: {} })); + + service.startFresh(); + await vi.waitFor(() => expect(mockAppSettings.resetSettings).toHaveBeenCalled()); + + // The valid user slot is retired; the app-less global slot is skipped, not retired. + expect(mockStorage.setConfig).toHaveBeenCalledWith( + 'user', 'uconf', expect.objectContaining({ app: expect.objectContaining({ configVersion: 0 }) }), 9); + expect(mockStorage.setConfig).not.toHaveBeenCalledWith( + 'global', 'gconf', expect.anything(), 9); + }); }); diff --git a/src/app/core/services/configuration-upgrade.service.ts b/src/app/core/services/configuration-upgrade.service.ts index 430a10dd..17540921 100644 --- a/src/app/core/services/configuration-upgrade.service.ts +++ b/src/app/core/services/configuration-upgrade.service.ts @@ -109,6 +109,8 @@ export class ConfigurationUpgradeService { setTimeout(() => this._settings.reloadApp(), 1500); } catch (error) { this.pushError('Error fetching configuration data: ' + (error as Error).message); + // Clear the blocking overlay so the error is visible, matching the v11/v12 paths. + this.upgrading.set(false); } } else if (version === 11) { @@ -179,11 +181,12 @@ export class ConfigurationUpgradeService { } else { // LocalStorage upgrade path for config version 10 - const localStorageConfig: v10IConfig = { app: null, widget: null, layout: null, theme: null }; - localStorageConfig.app = this._settings.loadConfigFromLocalStorage('appConfig'); - localStorageConfig.widget = this._settings.loadConfigFromLocalStorage('widgetConfig'); - localStorageConfig.layout = this._settings.loadConfigFromLocalStorage('layoutConfig'); - localStorageConfig.theme = this._settings.loadConfigFromLocalStorage('themeConfig'); + const localStorageConfig: v10IConfig = { + app: this._settings.loadConfigFromLocalStorage('appConfig'), + widget: this._settings.loadConfigFromLocalStorage('widgetConfig'), + layout: this._settings.loadConfigFromLocalStorage('layoutConfig'), + theme: this._settings.loadConfigFromLocalStorage('themeConfig') + }; const transformedApp = this.transformApp(localStorageConfig.app as IAppConfig); const transformedTheme = this.transformTheme(localStorageConfig.theme); @@ -216,6 +219,10 @@ export class ConfigurationUpgradeService { .then(async (rootConfigs: Config[]) => { for (const rootConfig of rootConfigs) { const oldConfiguration = await this._storage.getConfig(rootConfig.scope, rootConfig.name, this.legacyFileVersion) as unknown as IConfig; + if (!oldConfiguration.app) { + this.pushError(`[Upgrade] Configuration ${rootConfig.scope}/${rootConfig.name} has no app section; skipping retire.`); + continue; + } oldConfiguration.app.configVersion = 0; // retire try { // Await the retire write for BOTH scopes so it completes before the @@ -237,9 +244,14 @@ export class ConfigurationUpgradeService { // close handled by component dialog; service only reloads on upgrade path }); } else { - const localStorageConfig: IConfig = { app: null, dashboards: null, theme: null }; + const localStorageConfig: IConfig = { app: null, dashboards: [], theme: null }; localStorageConfig.app = this._settings.loadConfigFromLocalStorage('appConfig'); localStorageConfig.theme = this._settings.loadConfigFromLocalStorage('themeConfig'); + if (!localStorageConfig.app || !localStorageConfig.theme) { + this.pushError('[Upgrade Service] Cannot start fresh: local appConfig/themeConfig failed to load.'); + this.upgrading.set(false); + return; + } localStorageConfig.app.configVersion = MIGRATION_OUTPUT_VERSION; // baseline fresh localStorageConfig.app.nightModeBrightness = 0.27; localStorageConfig.theme.themeName = ''; @@ -254,7 +266,7 @@ export class ConfigurationUpgradeService { // eslint-disable-next-line @typescript-eslint/no-explicit-any private async transformConfig(rootConfig: Config): Promise { const config = await this._storage.getConfig(rootConfig.scope, rootConfig.name, this.legacyFileVersion) as unknown as v10IConfig; - if (config.app.configVersion !== this.legacyConfigVersion) { + if (!config.app || config.app.configVersion !== this.legacyConfigVersion) { this.pushError(`[Upgrade Service] ${rootConfig.scope}/${rootConfig.name} is not an upgradable version ${this.legacyConfigVersion} config. Skipping.`); return null; } @@ -301,7 +313,7 @@ export class ConfigurationUpgradeService { return config; } - private transformApp(app: IAppConfig): IAppConfig { + private transformApp(app: IAppConfig | null): IAppConfig | null { if (!app) return null; const clone = cloneDeep(app); clone.configVersion = MIGRATION_OUTPUT_VERSION; @@ -310,7 +322,7 @@ export class ConfigurationUpgradeService { return clone; } - private transformTheme(theme: v10IThemeConfig): IThemeConfig { + private transformTheme(theme: v10IThemeConfig): IThemeConfig | null { if (!theme) return null; const themeConfig: IThemeConfig = { themeName: '' }; return themeConfig; @@ -318,11 +330,12 @@ export class ConfigurationUpgradeService { private upgradeConfig(config: IConfig): IConfig | null { try { - if (config.app.configVersion !== 11) { - this.pushError(`[Upgrade Service] Config version ${config.app.configVersion} upgrade is not supported. Skipping...`); + const appConfig = config.app; + if (!appConfig || appConfig.configVersion !== 11) { + this.pushError(`[Upgrade Service] Config version ${appConfig?.configVersion} upgrade is not supported. Skipping...`); return null; } - this.removeSplitShellConfigKeys(config.app); + this.removeSplitShellConfigKeys(appConfig); this.migrateUseNeedleToEnableNeedle(config.dashboards); // Iterate dashboards and force widget selector to 'widget-host2' let updatedWidgetCount = 0; @@ -375,14 +388,14 @@ export class ConfigurationUpgradeService { this.pushMsg(`[Upgrade] Doubled widget grid metrics for ${dimensionUpdatedCount} non-zero (w/h/x/y) entries.`); } - config.app.configVersion = MIGRATION_OUTPUT_VERSION; + appConfig.configVersion = MIGRATION_OUTPUT_VERSION; return { - app: config.app, theme: config.theme, dashboards: config.dashboards + app: appConfig, theme: config.theme, dashboards: config.dashboards }; } catch (error) { - this.pushError(`[Upgrade Service] Error upgrading ${config.app.configVersion}: ${(error as Error).message}`); + this.pushError(`[Upgrade Service] Error upgrading ${config.app?.configVersion}: ${(error as Error).message}`); return null; } } @@ -394,12 +407,13 @@ export class ConfigurationUpgradeService { */ private upgradeConfigV12toV13(config: IConfig): IConfig | null { try { - if (config.app.configVersion !== 12) { - this.pushError(`[Upgrade Service] Config version ${config.app.configVersion} is not an upgradable v12 config. Skipping...`); + const appConfig = config.app; + if (!appConfig || appConfig.configVersion !== 12) { + this.pushError(`[Upgrade Service] Config version ${appConfig?.configVersion} is not an upgradable v12 config. Skipping...`); return null; } - delete (config.app as unknown as Record).dataSets; + delete (appConfig as unknown as Record).dataSets; if (Array.isArray(config.dashboards)) { for (const dash of config.dashboards) { @@ -415,8 +429,8 @@ export class ConfigurationUpgradeService { } } - config.app.configVersion = V13_MIGRATION_OUTPUT_VERSION; - return { app: config.app, theme: config.theme, dashboards: config.dashboards }; + appConfig.configVersion = V13_MIGRATION_OUTPUT_VERSION; + return { app: appConfig, theme: config.theme, dashboards: config.dashboards }; } catch (error) { this.pushError(`[Upgrade Service] Error upgrading v12->v13: ${(error as Error).message}`); return null; diff --git a/src/app/core/services/dashboard.service.ts b/src/app/core/services/dashboard.service.ts index fb108542..42dedc25 100644 --- a/src/app/core/services/dashboard.service.ts +++ b/src/app/core/services/dashboard.service.ts @@ -30,7 +30,7 @@ export class DashboardService { private readonly _destroyRef = inject(DestroyRef); public dashboards = signal([], { equal: isEqual }); public readonly activeDashboard = signal(null); - private _widgetAction = new BehaviorSubject(null); + private _widgetAction = new BehaviorSubject(null); public widgetAction$ = this._widgetAction.asObservable(); public isDashboardStatic = signal(true); public widgetClipboard = signal(null); @@ -284,10 +284,11 @@ export class DashboardService { * This only updates the internal state and does NOT trigger navigation or URL changes. */ public previousDashboard(): void { - if ((this.activeDashboard() - 1) < 0) { + const active = this.activeDashboard() ?? 0; + if ((active - 1) < 0) { this.activeDashboard.set(this.dashboards().length - 1); } else { - this.activeDashboard.set(this.activeDashboard() - 1); + this.activeDashboard.set(active - 1); } } @@ -297,10 +298,11 @@ export class DashboardService { * This only updates the internal state and does NOT trigger navigation or URL changes. */ public nextDashboard(): void { - if ((this.activeDashboard() + 1) > (this.dashboards().length) - 1) { + const active = this.activeDashboard() ?? 0; + if ((active + 1) > (this.dashboards().length) - 1) { this.activeDashboard.set(0); } else { - this.activeDashboard.set(this.activeDashboard() + 1); + this.activeDashboard.set(active + 1); } } @@ -331,11 +333,12 @@ export class DashboardService { * This updates the browser URL and triggers Angular routing. */ public navigateToNextDashboard(): void { - let nextDashboard: number = null; - if ((this.activeDashboard() + 1) >= this.dashboards().length) { + const active = this.activeDashboard() ?? 0; + let nextDashboard: number; + if ((active + 1) >= this.dashboards().length) { nextDashboard = 0; } else { - nextDashboard = this.activeDashboard() + 1; + nextDashboard = active + 1; } this._router.navigate(['/page', nextDashboard]); } @@ -346,11 +349,12 @@ export class DashboardService { * This updates the browser URL and triggers Angular routing. */ public navigateToPreviousDashboard(): void { - let nextDashboard: number = null; - if ((this.activeDashboard() - 1) < 0) { + const active = this.activeDashboard() ?? 0; + let nextDashboard: number; + if ((active - 1) < 0) { nextDashboard = this.dashboards().length - 1; } else { - nextDashboard = this.activeDashboard() - 1; + nextDashboard = active - 1; } this._router.navigate(['/page', nextDashboard]); } diff --git a/src/app/core/services/data.service.ts b/src/app/core/services/data.service.ts index 2af029dc..274c8622 100644 --- a/src/app/core/services/data.service.ts +++ b/src/app/core/services/data.service.ts @@ -42,7 +42,7 @@ const isRfc3339StringDate = (date: Date | string): boolean => { }; // Translate units from sk metadata to appropriate type category -const typeFromUnits = (units: string): string | undefined => { +const typeFromUnits = (units: string | undefined): string | undefined => { if (!units) { return undefined; } @@ -239,8 +239,8 @@ export class DataService implements OnDestroy { return matchingPaths.pathDataUpdate$; } - let currentValue: string = null; - let currentTimestamp: string = null; + let currentValue: string | null = null; + let currentTimestamp: string | null | undefined = null; let currentDateTimestamp: Date | null = null; let state: TState = States.Normal; let pathUpdate: IPathUpdate = { @@ -250,7 +250,7 @@ export class DataService implements OnDestroy { }, state: state }; - let metaUpdate: ISkMetadata = null; + let metaUpdate: ISkMetadata | null = null; const dataPath = this._skData.get(path); @@ -480,7 +480,7 @@ export class DataService implements OnDestroy { state: pendingState ?? States.Normal, defaultSource: undefined, sources: {}, - meta: meta.meta ? cloneDeep(meta.meta) : null, + meta: meta.meta ? cloneDeep(meta.meta) : undefined, }; this._skData.set(metaPath, pathObject); if (pendingState !== undefined) { @@ -611,7 +611,7 @@ export class DataService implements OnDestroy { } } - private setPathContext(context: string, path: string): string { + private setPathContext(context: string | undefined, path: string): string { const finalPath = context !== this._selfUrn ? `${context}.${path}` : `${SELFROOTDEF}.${path}`; return finalPath; } diff --git a/src/app/core/services/notifications.service.ts b/src/app/core/services/notifications.service.ts index 53221bd0..5932e2e3 100644 --- a/src/app/core/services/notifications.service.ts +++ b/src/app/core/services/notifications.service.ts @@ -63,10 +63,10 @@ export class NotificationsService implements OnDestroy { emergency: { sound: 4, visual: 2 }, }; - private _notificationSettingsSubscription: Subscription = null; - private _notificationDataStreamSubscription: Subscription = null; - private _notificationMetaStreamSubscription: Subscription = null; - private _resetServiceSubscription: Subscription = null; + private _notificationSettingsSubscription: Subscription; + private _notificationDataStreamSubscription: Subscription | null = null; + private _notificationMetaStreamSubscription: Subscription | null = null; + private _resetServiceSubscription: Subscription; private _notificationConfig: INotificationConfig; private _notificationConfig$ = new BehaviorSubject(DefaultNotificationConfig); @@ -78,10 +78,10 @@ export class NotificationsService implements OnDestroy { // --- HTMLAudioElement (audio) state ---------------------------------------- // Cache one player per track id and reuse across switches. private _players = new Map(); - private _activeAlarmSoundtrack: number = null; + private _activeAlarmSoundtrack: number | null = null; private _isMuted = false; - private _lastEmittedValue: IAlarmInfo = null; + private _lastEmittedValue: IAlarmInfo | null = null; constructor() { this._notificationSettingsSubscription = this.settings.getNotificationServiceConfigAsO() @@ -250,6 +250,10 @@ export class NotificationsService implements OnDestroy { } private getNotificationSeverity(message: INotification): { aSev: number; vSev: number } { + if (!message.value) { + return { aSev: 0, vSev: 0 }; + } + const state = message.value['state']; const severity = NotificationsService.ALARM_SEVERITIES[state]; if (!severity) { diff --git a/src/app/core/services/remote-dashboards.service.ts b/src/app/core/services/remote-dashboards.service.ts index a071821c..687f2a3f 100644 --- a/src/app/core/services/remote-dashboards.service.ts +++ b/src/app/core/services/remote-dashboards.service.ts @@ -85,7 +85,7 @@ export class RemoteDashboardsService { untracked(() => { if (!isRemoteControl && !this.previousIsRemoteControl) return; this.previousIsRemoteControl = isRemoteControl; - let screensPayload: IScreensPayload = undefined; + let screensPayload: IScreensPayload | null | undefined = undefined; if (!isRemoteControl) { // Clear displayName and screens on the server screensPayload = null; @@ -132,7 +132,7 @@ export class RemoteDashboardsService { untracked(() => { if (!this.isRemoteControl()) return; - if (changeTo.data.value == null) return; + if (changeTo === undefined || changeTo.data.value == null) return; const idx = Number(changeTo.data.value); if (!isNaN(idx) && idx >= 0 && idx < this.dashboard.dashboards().length) { if (this.dashboard.activeDashboard() !== idx) { @@ -156,7 +156,7 @@ export class RemoteDashboardsService { return { displayName: displayName, screens: dashboardListItems }; } - private shareScreens(screens: IScreensPayload): void { + private shareScreens(screens: IScreensPayload | null | undefined): void { this.setScreensOnRemote(this.KIP_UUID, screens) console.log('[Remote Dashboards] Sending dashboard configurations to server.'); } @@ -196,10 +196,10 @@ export class RemoteDashboardsService { * }); * ``` */ - public setScreensOnRemote(kipId: string, screensPayload: IScreensPayload): void { + public setScreensOnRemote(kipId: string, screensPayload: IScreensPayload | null | undefined): void { const payload: IRemoteDisplayCommand = { displayId: kipId, - display: screensPayload === null ? null : { ...screensPayload } + display: screensPayload == null ? null : { ...screensPayload } }; const requestId = this.requests.putRequest(this.COMMAND_SET_DISPLAY_PATH, payload, this.KIP_UUID); if (!requestId) { diff --git a/src/app/core/services/settings.service.ts b/src/app/core/services/settings.service.ts index 26fdcb17..0ff4fd20 100644 --- a/src/app/core/services/settings.service.ts +++ b/src/app/core/services/settings.service.ts @@ -107,14 +107,15 @@ export class SettingsService { private async startup(): Promise { // A missing server config comes back as {} (not a 404), so guard on the presence of app config — // an empty/appless object must not fall through to pushSettings() and dereference activeConfig.app. - if (!this.storage.isRemoteContextBootstrapped() || !this.storage.initConfig?.app) { + const initConfig = this.storage.initConfig; + if (!this.storage.isRemoteContextBootstrapped() || !initConfig?.app) { console.warn('[AppSettings Service] Shared configuration enabled but remote bootstrap handoff is missing or empty. Waiting for explicit recovery action.'); return; } - this.configVersion = this.storage.initConfig?.app?.configVersion; - this.checkConfigUpgradeRequired(false, this.storage.initConfig?.app?.configVersion); - this.activeConfig = this.storage.initConfig; + this.configVersion = initConfig.app.configVersion; + this.checkConfigUpgradeRequired(false, initConfig.app.configVersion); + this.activeConfig = initConfig; this.pushSettings(); } @@ -222,28 +223,35 @@ export class SettingsService { } private pushSettings(): void { + const app = this.activeConfig.app; + // Guaranteed non-null by startup()'s pre-check before pushSettings() is invoked; guarded again + // here defensively rather than asserted, since activeConfig is a mutable field. + if (!app) { + return; + } + if (this.activeConfig.theme) { this._themeName.set(this.activeConfig.theme.themeName); } - this.applyUnitDefaults(this.activeConfig.app.unitDefaults); - this.applyNotificationConfig(this.activeConfig.app.notificationConfig); + this.applyUnitDefaults(app.unitDefaults); + this.applyNotificationConfig(app.notificationConfig); - if (this.activeConfig.app.autoNightMode === undefined) { + if (app.autoNightMode === undefined) { this.setAutoNightMode(false); } else { - this._autoNightMode.set(this.activeConfig.app.autoNightMode); + this._autoNightMode.set(app.autoNightMode); } - if (this.activeConfig.app.redNightMode === undefined) { + if (app.redNightMode === undefined) { this.setRedNightMode(false); } else { - this._redNightMode.set(this.activeConfig.app.redNightMode); + this._redNightMode.set(app.redNightMode); } - if (this.activeConfig.app.nightModeBrightness === undefined) { + if (app.nightModeBrightness === undefined) { this.setNightModeBrightness(0.2); } else { - this._nightModeBrightness.set(this.activeConfig.app.nightModeBrightness); + this._nightModeBrightness.set(app.nightModeBrightness); } if (this.activeConfig.dashboards === undefined) { @@ -252,10 +260,10 @@ export class SettingsService { this._dashboards = this.activeConfig.dashboards; } - if (this.activeConfig.app.browserTabTitle === undefined) { + if (app.browserTabTitle === undefined) { this._browserTabTitle.set('SKip'); } else { - this._browserTabTitle.set(this.activeConfig.app.browserTabTitle); + this._browserTabTitle.set(app.browserTabTitle); } } diff --git a/src/app/core/services/signalk-connection.service.spec.ts b/src/app/core/services/signalk-connection.service.spec.ts new file mode 100644 index 00000000..6ef43171 --- /dev/null +++ b/src/app/core/services/signalk-connection.service.spec.ts @@ -0,0 +1,54 @@ +import { TestBed } from '@angular/core/testing'; +import { HttpClient, HttpResponse } from '@angular/common/http'; +import { beforeEach, describe, expect, it, vi } from 'vitest'; +import { SignalKConnectionService } from './signalk-connection.service'; +import { ConnectionStateMachine } from './connection-state-machine.service'; + +describe('SignalKConnectionService', () => { + let service: SignalKConnectionService; + + const mockStateMachine = { setHTTPRetryCallback: vi.fn() }; + + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [ + SignalKConnectionService, + { provide: ConnectionStateMachine, useValue: mockStateMachine }, + { provide: HttpClient, useValue: {} } + ] + }); + service = TestBed.inject(SignalKConnectionService); + }); + + // processEndpointResponse is private; exercise it directly to pin the endpoint-parsing + // contract, including the fail-loud behavior for a malformed discovery response. + const parseEndpoint = (body: unknown, proxyEnabled = false) => + (service as unknown as { + processEndpointResponse: (r: unknown, p?: boolean, s?: boolean) => { operation: number; httpServiceUrl: string | null }; + }).processEndpointResponse(new HttpResponse({ body, status: 200 }), proxyEnabled); + + const wellFormedBody = { + server: { id: 'signalk-server', version: '2.0.0' }, + endpoints: { v1: { 'signalk-http': 'http://host:3000/signalk/v1/api/', 'signalk-ws': 'ws://host:3000/signalk/v1/stream' } } + }; + + describe('processEndpointResponse', () => { + it('returns a connected (operation 2) endpoint for a well-formed v1 response', () => { + const status = parseEndpoint(wellFormedBody); + expect(status.operation).toBe(2); + expect(status.httpServiceUrl).toBe('http://host:3000/signalk/v1/api/'); + }); + + it('throws when the response has no body', () => { + expect(() => parseEndpoint(null)).toThrow(); + }); + + it('throws when the v1 WebSocket URL is absent (fail-loud, no partial connect)', () => { + const noWs = { + server: { id: 'signalk-server', version: '2.0.0' }, + endpoints: { v1: { 'signalk-http': 'http://host:3000/signalk/v1/api/' } } + }; + expect(() => parseEndpoint(noWs)).toThrow(); + }); + }); +}); diff --git a/src/app/core/services/signalk-connection.service.ts b/src/app/core/services/signalk-connection.service.ts index 293cd650..f7a59b22 100644 --- a/src/app/core/services/signalk-connection.service.ts +++ b/src/app/core/services/signalk-connection.service.ts @@ -1,6 +1,6 @@ import { inject, Injectable } from '@angular/core'; import { BehaviorSubject, catchError, lastValueFrom, throwError, timeout } from 'rxjs'; -import { HttpClient, HttpErrorResponse } from '@angular/common/http'; +import { HttpClient, HttpErrorResponse, HttpResponse } from '@angular/common/http'; import { ISignalKUrl } from '../interfaces/app-settings.interfaces'; import { ConnectionStateMachine } from './connection-state-machine.service'; @@ -38,10 +38,10 @@ interface ISignalKEndpointResponse { export interface IEndpointStatus { operation: number; message: string; - serverDescription: string; - httpServiceUrl: string; // v1 API endpoint + serverDescription: string | null; + httpServiceUrl: string | null; // v1 API endpoint httpServiceUrlV2?: string; // v2 API endpoint (if available) - WsServiceUrl: string; + WsServiceUrl: string | null; WsServiceUrlV2?: string; // v2 WebSocket endpoint (if available) subscribeAll?: boolean; } @@ -71,8 +71,8 @@ export class SignalKConnectionService { // Server information public signalKURL: ISignalKUrl; - private serverName: string; - public serverVersion$ = new BehaviorSubject(null); + private serverName: string | undefined; + public serverVersion$ = new BehaviorSubject(null); private serverRoles: string[] = []; private http = inject(HttpClient); @@ -298,10 +298,13 @@ export class SignalKConnectionService { * @returns Configured endpoint status object */ private processEndpointResponse( - endpointResponse: { body: ISignalKEndpointResponse; status: number }, + endpointResponse: HttpResponse, proxyEnabled?: boolean, subscribeAll?: boolean ): IEndpointStatus { + if (!endpointResponse.body) { + throw new Error("Signal K server response did not include a body"); + } console.debug("[Connection Service] Signal K HTTP Endpoints retrieved"); this.serverVersion$.next(endpointResponse.body.server.version); @@ -310,6 +313,10 @@ export class SignalKConnectionService { const httpUrlV2 = endpointResponse.body.endpoints.v2?.["signalk-http"]; const wsUrlV2 = endpointResponse.body.endpoints.v2?.["signalk-ws"]; + if (!httpUrl || !wsUrl) { + throw new Error("Signal K server response is missing required v1 endpoint URLs"); + } + const serverServiceEndpoints: IEndpointStatus = { operation: 2, message: endpointResponse.status?.toString() || "Connected", @@ -368,17 +375,17 @@ export class SignalKConnectionService { return this.serverServiceEndpoint$.asObservable(); } - public setServerInfo(name: string, version: string, roles: string[]): void { + public setServerInfo(name: string | undefined, version: string | undefined, roles: string[] | undefined): void { this.serverName = name; - this.serverRoles = roles; + this.serverRoles = roles ?? []; console.log(`[Connection Service] Server Name: ${name}, Version: ${version}, Roles: ${JSON.stringify(roles)}`); } - public get skServerName() : string { + public get skServerName() : string | undefined { return this.serverName; } - public get skServerVersion() : string { + public get skServerVersion() : string | null { return this.serverVersion$.getValue(); } diff --git a/src/app/core/services/signalk-delta.service.spec.ts b/src/app/core/services/signalk-delta.service.spec.ts index 443362d3..e75d7265 100644 --- a/src/app/core/services/signalk-delta.service.spec.ts +++ b/src/app/core/services/signalk-delta.service.spec.ts @@ -338,6 +338,9 @@ describe('SignalKDeltaService', () => { service.subscribeRequestUpdates().subscribe(v => reqs.push(v)); parse(service, { requestId: 'req-1', updates: [update([{ path: 'navigation.speedOverGround', value: 1 }])] }); expect(out).toHaveLength(1); + // A message with no context field emits context: undefined (DataService folds it to self). + // Pin it so a refactor coercing undefined -> '' or a literal URN is caught. + expect(out[0].context).toBeUndefined(); expect(reqs).toEqual([]); }); diff --git a/src/app/core/services/signalk-delta.service.ts b/src/app/core/services/signalk-delta.service.ts index 08572e51..091efc05 100644 --- a/src/app/core/services/signalk-delta.service.ts +++ b/src/app/core/services/signalk-delta.service.ts @@ -59,7 +59,7 @@ export class SignalKDeltaService implements OnDestroy { // Self URN message stream Observer private _vesselSelfUrn$ = new Subject(); // local self URN to filter data based on root node (self or others) - private _selfUrn: string = undefined; + private _selfUrn: string | undefined = undefined; // Delta Service Endpoint status publishing public streamEndpoint: IStreamStatus = { @@ -73,7 +73,7 @@ export class SignalKDeltaService implements OnDestroy { // full delta firehose; path selection happens in DataService and per-widget rate limiting in // WidgetStreamsDirective (sampleTime). We intentionally do not emit per-path SK subscribe/unsubscribe deltas or use // SK subscription policies (policy/format/minPeriod), so no such controls exist in widget config. - private endpointWS: string = null; + private endpointWS: string | null = null; private SubscriptionType = "self"; private readonly WS_CONNECTION_SUBSCRIBE = "?subscribe="; private readonly WS_CONNECTION_META = "&sendMeta=all"; // default but we could use none + specific paths in the future @@ -280,6 +280,9 @@ export class SignalKDeltaService implements OnDestroy { * authenticates the WS upgrade, so no auth token is ever appended. */ private buildWebSocketUrl(): string { + if (!this.endpointWS) { + throw new Error('[Delta Service] No WebSocket endpoint available to build URL from'); + } const args = this.WS_CONNECTION_SUBSCRIBE + this.SubscriptionType + this.WS_CONNECTION_META; return this.endpointWS + args; } @@ -356,7 +359,7 @@ export class SignalKDeltaService implements OnDestroy { console.warn("[Delta Service] Unknown message type. Message content:" + message); } - private parseUpdates(updates: ISignalKUpdateMessage[], context: string): void { + private parseUpdates(updates: ISignalKUpdateMessage[], context: string | undefined): void { // if (context != this._selfUrn) { // remove non self root nodes // return; // } @@ -480,7 +483,7 @@ export class SignalKDeltaService implements OnDestroy { return results; } - private parseSkMeta(metadata: ISignalKMeta, context: string) { + private parseSkMeta(metadata: ISignalKMeta, context: string | undefined) { if (metadata?.value == null) { console.warn("[Delta Service] Dropping metadata update without a value:", metadata); return; diff --git a/src/app/core/services/signalk-requests.service.ts b/src/app/core/services/signalk-requests.service.ts index 5d04d9e2..ae33362d 100644 --- a/src/app/core/services/signalk-requests.service.ts +++ b/src/app/core/services/signalk-requests.service.ts @@ -24,8 +24,8 @@ const handledStatusCodes = new Set([200, 202, 400, 401, 403, 405, 500, 502, 504] const serverErrorStatusCodes = new Set([500, 502, 504]); export interface skRequest { requestId: string; - state: string; - statusCode: number; + state: string | null; + statusCode: number | null; statusCodeDescription?: string; widgetUUID?: string; message?: string; @@ -107,43 +107,43 @@ export class SignalkRequestsService { private updateRequest(delta: ISignalKDeltaMessage) { const index = this.requests.findIndex(r => r.requestId == delta.requestId); if (index > -1) { // exists in local array - this.requests[index].state = delta.state; - this.requests[index].statusCode = delta.statusCode; + const statusCode = delta.statusCode; + this.requests[index].state = delta.state ?? null; + this.requests[index].statusCode = statusCode ?? null; this.requests[index].message = delta.message; - const currentStatusCode = deltaStatusCodes[delta.statusCode]; + const currentStatusCode = statusCode !== undefined ? deltaStatusCodes[statusCode] : undefined; - if ((typeof currentStatusCode != 'undefined') && handledStatusCodes.has(this.requests[index].statusCode)) { + if (statusCode !== undefined && (typeof currentStatusCode != 'undefined') && handledStatusCodes.has(statusCode)) { this.requests[index].statusCodeDescription = currentStatusCode; - if (this.requests[index].statusCode == 202) { + if (statusCode == 202) { console.log("[Request Service] Async 202 response received"); return; } - if (this.requests[index].statusCode == 400) { - this.toast.show(this.requests[index].message, 0, false, 'error'); + if (statusCode == 400) { + this.toast.show(this.requests[index].message ?? '', 0, false, 'error'); console.log("[Request Service] " + this.requests[index].message ); } - if (this.requests[index].statusCode == 403) { - console.warn("[Request Service] Status Code: " + this.requests[index].statusCode + " - " + this.requests[index].statusCodeDescription); + if (statusCode == 403) { + console.warn("[Request Service] Status Code: " + statusCode + " - " + currentStatusCode); } - if (this.requests[index].statusCode == 405) { - console.error("[Request Service] Status Code: " + this.requests[index].statusCode + " - " + this.requests[index].message); + if (statusCode == 405) { + console.error("[Request Service] Status Code: " + statusCode + " - " + this.requests[index].message); } - if (serverErrorStatusCodes.has(this.requests[index].statusCode)) { - const description = this.requests[index].statusCodeDescription; - const detail = this.requests[index].message ? description + " - " + this.requests[index].message : description; + if (serverErrorStatusCodes.has(statusCode)) { + const detail = this.requests[index].message ? currentStatusCode + " - " + this.requests[index].message : currentStatusCode; this.toast.show(detail, 0, false, 'error'); - console.error("[Request Service] Status Code: " + this.requests[index].statusCode + " - " + description); + console.error("[Request Service] Status Code: " + statusCode + " - " + currentStatusCode); } } else { - this.toast.show("Unknown Request Status Code received: " + this.requests[index].statusCode + " - " + deltaStatusCodes[this.requests[index].statusCode] + " - " + this.requests[index].message, 0, false, 'error'); - console.error("[Request Service] Unknown Request Status Code received: " + this.requests[index].statusCode + " - " + deltaStatusCodes[this.requests[index].statusCode] + " - " + this.requests[index].message); + this.toast.show("Unknown Request Status Code received: " + statusCode + " - " + currentStatusCode + " - " + this.requests[index].message, 0, false, 'error'); + console.error("[Request Service] Unknown Request Status Code received: " + statusCode + " - " + currentStatusCode + " - " + this.requests[index].message); } try { this.requestStatus$.next(this.requests[index]); // dispatched results diff --git a/src/app/core/services/storage.service.ts b/src/app/core/services/storage.service.ts index 6865c8b5..5fc27bac 100644 --- a/src/app/core/services/storage.service.ts +++ b/src/app/core/services/storage.service.ts @@ -52,15 +52,15 @@ export class StorageService { private http = inject(HttpClient); private readonly _auth = inject(AuthenticationService); - private serverEndpoint: string = null; + private serverEndpoint: string | null = null; public isAppDataSupported = false; - private configFileVersion: number = null; + private configFileVersion: number | null = null; public sharedConfigName: string; - private InitConfig: IConfig = null; + private InitConfig: IConfig | null = null; private _isRemoteContextBootstrapped = false; public storageServiceReady$ = new BehaviorSubject(false); private _isLoggedIn = false; - private _networkStatus: IEndpointStatus = undefined; + private _networkStatus: IEndpointStatus | undefined = undefined; // Instrumentation toggle private _logIO = false; // set to false to silence logging @@ -279,8 +279,11 @@ export class StorageService { this.ensureReady(); const serverConfigs: Config[] = []; if (!this.serverEndpoint) { + // Unreachable in practice: ensureReady() only passes once isStorageServiceReady() has + // observed a truthy serverEndpoint, and nothing ever clears it afterward. Kept as a + // defensive fallback that degrades to "no configs" rather than a crash. console.warn("[Storage Service] No server endpoint set. Cannot retrieve config list"); - return null; + return serverConfigs; } const base = this.serverEndpoint; @@ -344,8 +347,7 @@ export class StorageService { if (isInitLoad) this.InitConfig = remoteConfig; return cloneDeep(remoteConfig); } catch (error) { - this.handleError(error as HttpErrorResponse); // throws - return null; // unreachable + this.handleError(error as HttpErrorResponse); // never returns } } @@ -590,13 +592,13 @@ export class StorageService { } } - private handleError(error: HttpErrorResponse) { + private handleError(error: HttpErrorResponse): never { this.logError(error); // Rethrow so awaiting callers (get/set/list) observe the failure. throw error; } - public get initConfig(): IConfig { + public get initConfig(): IConfig | null { return this.InitConfig; } } diff --git a/src/app/widget-config/path-control-config/path-control-config.component.ts b/src/app/widget-config/path-control-config/path-control-config.component.ts index f53c4e30..a07497b3 100644 --- a/src/app/widget-config/path-control-config/path-control-config.component.ts +++ b/src/app/widget-config/path-control-config/path-control-config.component.ts @@ -174,7 +174,7 @@ export class PathControlConfigComponent implements OnInit, OnChanges { if (isMultiCTRLTypeLight) { supportsPUT = false; } else { - supportsPUT = compare(this._connection.skServerVersion, '2.12.0', ">=") ? pathFormGroup.value.supportsPut : false; + supportsPUT = this._connection.skServerVersion != null && compare(this._connection.skServerVersion, '2.12.0', ">=") ? pathFormGroup.value.supportsPut : false; } } diff --git a/tsconfig.betterer.json b/tsconfig.betterer.json new file mode 100644 index 00000000..79d6ac7b --- /dev/null +++ b/tsconfig.betterer.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "module": "commonjs", + "moduleResolution": "node", + "esModuleInterop": true, + "target": "ES2022", + "skipLibCheck": true, + "types": ["node"] + } +} diff --git a/tsconfig.strict.json b/tsconfig.strict.json new file mode 100644 index 00000000..b986da88 --- /dev/null +++ b/tsconfig.strict.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "strictNullChecks": true, + "noEmit": true + }, + "include": ["src/**/*.ts"], + "exclude": ["src/**/*.spec.ts", "src/test.ts"] +}