a reactive (signals based) hypermedia web framework (wip) stormlightlabs.github.io/volt/
hypermedia frontend signals

chore: run linter

+1 -1
lib/eslint.config.js
··· 17 17 { 18 18 languageOptions: { 19 19 globals: { ...globals.browser, ...globals.node }, 20 - parserOptions: { project: "./tsconfig.json", tsconfigRootDir: import.meta.dirname }, 20 + parserOptions: { tsconfigRootDir: import.meta.dirname }, 21 21 }, 22 22 rules: { 23 23 "no-undef": "off",
+2 -1
lib/package.json
··· 37 37 "prepublishOnly": "pnpm build && pnpm test:run", 38 38 "publish:npm": "npm publish --access=public", 39 39 "publish:jsr": "npx jsr publish", 40 - "publish:all": "pnpm publish:npm && pnpm publish:jsr" 40 + "publish:all": "pnpm publish:npm && pnpm publish:jsr", 41 + "lint": "eslint . --fix" 41 42 }, 42 43 "publishConfig": { "access": "public" }, 43 44 "devDependencies": {
+12 -12
lib/test/core/http.test.ts
··· 347 347 348 348 it("sets loading state", () => { 349 349 setLoadingState(element); 350 - expect(element.getAttribute("data-volt-loading")).toBe("true"); 350 + expect(element.dataset.voltLoading).toBe("true"); 351 351 }); 352 352 353 353 it("sets error state", () => { 354 354 setErrorState(element, "Network error"); 355 - expect(element.getAttribute("data-volt-error")).toBe("Network error"); 355 + expect(element.dataset.voltError).toBe("Network error"); 356 356 }); 357 357 358 358 it("clears states", () => { 359 - element.setAttribute("data-volt-loading", "true"); 360 - element.setAttribute("data-volt-error", "Some error"); 359 + element.dataset.voltLoading = "true"; 360 + element.dataset.voltError = "Some error"; 361 361 362 362 clearStates(element); 363 363 364 - expect(element.hasAttribute("data-volt-loading")).toBe(false); 365 - expect(element.hasAttribute("data-volt-error")).toBe(false); 364 + expect(Object.hasOwn(element.dataset, "voltLoading")).toBe(false); 365 + expect(Object.hasOwn(element.dataset, "voltError")).toBe(false); 366 366 }); 367 367 368 368 it("dispatches volt:loading event", () => { ··· 627 627 button.click(); 628 628 629 629 await vi.waitFor(() => { 630 - expect(button.getAttribute("data-volt-loading")).toBe("true"); 630 + expect(button.dataset.voltLoading).toBe("true"); 631 631 }); 632 632 633 633 resolveRequest?.( ··· 641 641 ); 642 642 643 643 await vi.waitFor(() => { 644 - expect(button.hasAttribute("data-volt-loading")).toBe(false); 644 + expect(Object.hasOwn(button.dataset, "voltLoading")).toBe(false); 645 645 }); 646 646 }); 647 647 ··· 657 657 button.click(); 658 658 659 659 await vi.waitFor(() => { 660 - expect(button.getAttribute("data-volt-error")).toContain("Server error"); 660 + expect(button.dataset.voltError).toContain("Server error"); 661 661 }); 662 662 }); 663 663 }); ··· 775 775 button.click(); 776 776 777 777 await vi.waitFor(() => { 778 - const errorAttr = result.getAttribute("data-volt-error"); 778 + const errorAttr = result.dataset.voltError; 779 779 expect(errorAttr).toBeTruthy(); 780 780 expect(errorAttr).toContain("404"); 781 781 }); ··· 800 800 button.click(); 801 801 802 802 await vi.waitFor(() => { 803 - expect(result.getAttribute("data-volt-error")).toBeTruthy(); 803 + expect(result.dataset.voltError).toBeTruthy(); 804 804 }); 805 805 806 806 expect(mockFetch).toHaveBeenCalledTimes(3); ··· 967 967 }); 968 968 969 969 await vi.waitFor(() => { 970 - expect(button.getAttribute("data-volt-error")).toBeTruthy(); 970 + expect(button.dataset.voltError).toBeTruthy(); 971 971 expect(spinner.style.display).toBe("none"); 972 972 }, { timeout: 1000 }); 973 973 });
+2 -2
lib/test/core/ssr.test.ts
··· 65 65 66 66 it("returns true for hydrated elements", () => { 67 67 const el = document.createElement("div"); 68 - el.setAttribute("data-volt-hydrated", "true"); 68 + el.dataset.voltHydrated = "true"; 69 69 expect(isHydrated(el)).toBe(true); 70 70 }); 71 71 }); ··· 180 180 181 181 hydrate(); 182 182 183 - const el = document.getElementById("app")!; 183 + const el = document.querySelector("#app")!; 184 184 expect(isHydrated(el)).toBe(true); 185 185 }); 186 186
+7 -18
lib/test/plugins/shift.test.ts
··· 49 49 globalThis.matchMedia = vi.fn().mockReturnValue({ matches: false }); 50 50 51 51 element.animate = vi.fn((keyframes: Keyframe[], options?: KeyframeAnimationOptions) => { 52 - return { 53 - onfinish: null, 54 - cancel: vi.fn(), 55 - _keyframes: keyframes, 56 - _options: options, 57 - }; 52 + return { onfinish: null, cancel: vi.fn(), _keyframes: keyframes, _options: options }; 58 53 }) as unknown as typeof element.animate; 59 54 }); 60 55 ··· 79 74 80 75 it("should register custom animation", () => { 81 76 const customAnimation: AnimationPreset = { 82 - keyframes: [ 83 - { offset: 0, transform: "scale(1)" }, 84 - { offset: 1, transform: "scale(1.5)" }, 85 - ], 77 + keyframes: [{ offset: 0, transform: "scale(1)" }, { offset: 1, transform: "scale(1.5)" }], 86 78 duration: 500, 87 79 iterations: 1, 88 80 timing: "ease", ··· 135 127 136 128 registerAnimation("bounce", customAnimation); 137 129 expect(consoleSpy).toHaveBeenCalledWith( 138 - expect.stringContaining('Overriding built-in animation preset: "bounce"'), 130 + expect.stringContaining("Overriding built-in animation preset: \"bounce\""), 139 131 ); 140 132 141 133 consoleSpy.mockRestore(); ··· 186 178 shiftPlugin(mockContext, "unknown"); 187 179 188 180 expect(element.animate).not.toHaveBeenCalled(); 189 - expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('Unknown animation preset: "unknown"')); 181 + expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Unknown animation preset: \"unknown\"")); 190 182 191 183 consoleSpy.mockRestore(); 192 184 }); ··· 241 233 242 234 it("should handle signal not found", () => { 243 235 const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => {}); 244 - mockContext.findSignal = vi.fn().mockReturnValue(undefined); 236 + mockContext.findSignal = vi.fn().mockReturnValue(void 0); 245 237 246 238 shiftPlugin(mockContext, "missing:bounce"); 247 239 248 - expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('Signal "missing" not found')); 240 + expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Signal \"missing\" not found")); 249 241 consoleSpy.mockRestore(); 250 242 }); 251 243 ··· 290 282 291 283 describe("Animation Cleanup", () => { 292 284 it("should cancel animation on finish", () => { 293 - const mockAnimation = { 294 - onfinish: null as (() => void) | null, 295 - cancel: vi.fn(), 296 - }; 285 + const mockAnimation = { onfinish: null as (() => void) | null, cancel: vi.fn() }; 297 286 298 287 element.animate = vi.fn().mockReturnValue(mockAnimation); 299 288
+43 -1
pnpm-lock.yaml
··· 37 37 version: 8.46.1(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3) 38 38 vitest: 39 39 specifier: ^3.2.4 40 - version: 3.2.4(@types/node@24.8.1)(esbuild@0.25.11)(jiti@2.6.1)(jsdom@27.0.0(postcss@8.5.6))(terser@5.44.0)(yaml@2.8.1) 40 + version: 3.2.4(@types/node@24.8.1)(esbuild@0.25.11)(jiti@2.6.1)(jsdom@27.0.0)(terser@5.44.0)(yaml@2.8.1) 41 41 42 42 dev: 43 43 dependencies: ··· 5656 5656 - yaml 5657 5657 5658 5658 vitest@3.2.4(@types/node@24.8.1)(esbuild@0.25.11)(jiti@2.6.1)(jsdom@27.0.0(postcss@8.5.6))(terser@5.44.0)(yaml@2.8.1): 5659 + dependencies: 5660 + '@types/chai': 5.2.2 5661 + '@vitest/expect': 3.2.4 5662 + '@vitest/mocker': 3.2.4(rolldown-vite@7.1.14(@types/node@24.8.1)(esbuild@0.25.11)(jiti@2.6.1)(terser@5.44.0)(yaml@2.8.1)) 5663 + '@vitest/pretty-format': 3.2.4 5664 + '@vitest/runner': 3.2.4 5665 + '@vitest/snapshot': 3.2.4 5666 + '@vitest/spy': 3.2.4 5667 + '@vitest/utils': 3.2.4 5668 + chai: 5.3.3 5669 + debug: 4.4.3 5670 + expect-type: 1.2.2 5671 + magic-string: 0.30.19 5672 + pathe: 2.0.3 5673 + picomatch: 4.0.3 5674 + std-env: 3.10.0 5675 + tinybench: 2.9.0 5676 + tinyexec: 0.3.2 5677 + tinyglobby: 0.2.15 5678 + tinypool: 1.1.1 5679 + tinyrainbow: 2.0.0 5680 + vite: rolldown-vite@7.1.14(@types/node@24.8.1)(esbuild@0.25.11)(jiti@2.6.1)(terser@5.44.0)(yaml@2.8.1) 5681 + vite-node: 3.2.4(@types/node@24.8.1)(esbuild@0.25.11)(jiti@2.6.1)(terser@5.44.0)(yaml@2.8.1) 5682 + why-is-node-running: 2.3.0 5683 + optionalDependencies: 5684 + '@types/node': 24.8.1 5685 + jsdom: 27.0.0(postcss@8.5.6) 5686 + transitivePeerDependencies: 5687 + - esbuild 5688 + - jiti 5689 + - less 5690 + - msw 5691 + - sass 5692 + - sass-embedded 5693 + - stylus 5694 + - sugarss 5695 + - supports-color 5696 + - terser 5697 + - tsx 5698 + - yaml 5699 + 5700 + vitest@3.2.4(@types/node@24.8.1)(esbuild@0.25.11)(jiti@2.6.1)(jsdom@27.0.0)(terser@5.44.0)(yaml@2.8.1): 5659 5701 dependencies: 5660 5702 '@types/chai': 5.2.2 5661 5703 '@vitest/expect': 3.2.4