Skip to content

Convert SigPlot to Typescript#20

Draft
mrecachinas wants to merge 23 commits intospectriclabs:mainfrom
mrecachinas:typescript
Draft

Convert SigPlot to Typescript#20
mrecachinas wants to merge 23 commits intospectriclabs:mainfrom
mrecachinas:typescript

Conversation

@mrecachinas
Copy link

@mrecachinas mrecachinas commented Mar 10, 2026

This branches off #18 FYI

mrecachinas and others added 23 commits March 8, 2026 14:40
Replace dated build tooling with modern equivalents:

- esbuild replaces Browserify + Babel + Closure Compiler (~200× faster builds)
  Outputs: UMD, minified, ESM, and plugins bundles
- ESLint 9 (flat config) replaces JSHint with auto-fixable rules
- Prettier replaces jsbeautifier for code formatting
- GitHub Actions CI updated: Node 20, modern action versions, lint+build jobs
- package.json: add 'module' and 'exports' fields for dual CJS/ESM publish
- Grunt tooling preserved under 'grunt:*' scripts for backward compatibility

Legacy files (.jshintrc, .jsbeautifyrc, Gruntfile.js, karma.conf.js) kept
for now — will be removed after full migration.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Vite config for instant HMR dev server (replaces budo)
- Vitest config with jsdom environment for unit tests
- Vitest browser mode configured (Playwright/Chromium) for canvas tests
- Setup file that makes sigplot globally available for tests
- Smoke test suite (11 tests) validating build output and core APIs
- npm scripts: 'dev', 'test', 'test:watch', 'test:browser'

Existing QUnit tests remain runnable via 'npm run grunt:test'.
New tests use Vitest API — existing tests can be migrated incrementally.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Migrate all 18 source files in js/ from the CommonJS IIFE pattern:
  (function() { var x = require(...); module.exports = X; }());
to standard ES module syntax:
  import x from './x.js'; export default X;

- Remove IIFE wrappers from all files
- Convert require() to import (with .js extension for relative paths)
- Convert module.exports to export default
- Update ESLint config sourceType to 'module'
- esbuild handles the ES module bundling natively

No behavioral changes — same bundle output, same API surface.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Remove 35+ packages and 7 config files:
- Gruntfile.js, karma.conf.js, .jshintrc, .jsbeautifyrc, .travis.yml, .nvmrc
- All grunt-* plugins (12 packages)
- Karma + launchers + adapters (5 packages)
- Babel toolchain (3 packages)
- QUnit, Jasmine, and related test deps
- JSDoc template deps (catharsis, marked, minami, taffydb)
- budo dev server, travis CLI

Net result: 33 devDependencies → 14, dependencies: 8 → 7
Build toolchain is now: esbuild + ESLint + Prettier + Vitest + Vite

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Convert math, graphics, and colormap tests from QUnit to Vitest:
- tests.m.test.js: sec2tod time formatting tests
- tests.mx.test.js: format_f, real_to_pixel, distance, box tests
- tests.colormap.test.js: ColorMap construction with various color formats

Migration pattern: QUnit.test → it(), assert.equal → expect().toBe(),
assert.close → expect(Math.abs()).toBeLessThanOrEqual()

Total: 4 test files, 17 tests, all passing.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
These tests have been migrated to Vitest (.test.js files).
The HTML test runners are no longer needed (Vitest replaces Karma).

Remaining QUnit files (tests.js, tests.sigplot.js, tests.interactive-*.js)
are kept for reference — they require real browser canvas and will be
migrated when Vitest browser mode is fully set up.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Convert tests.sigplot.js from QUnit to Vitest API:
- 17 tests pass in jsdom (Plot construction, overlay, layers, zoom, etc.)
- 8 tests skipped: need real browser (layout-dependent or XHR-based)
- Enhanced vitest.setup.js with canvas 2D context stub for jsdom
- Removed migrated QUnit files (tests.sigplot.js, tests.js)

Remaining unmigrated: 12 interactive test files (manual visual verification
tests using interactiveTest() — these prompt humans to verify rendering).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Remove .jshintignore (JSHint no longer used)
- Remove .npmignore (empty; package.json 'files' field handles publishing)
- Trim .gitignore from 100+ lines of boilerplate to ~25 relevant entries

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- engines: node >= 18
- Dependabot: weekly npm + GitHub Actions updates
- Groups: dev deps (minor/patch), prod deps (minor/patch), actions

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Remove underscore dependency — all 11 usages replaced with builtins:
- _.clone(obj) → Object.assign({}, obj)
- _.has(obj, key) → Object.prototype.hasOwnProperty.call(obj, key)
- _.indexOf(arr, val) → arr.indexOf(val)
- _.isFunction(fn) → typeof fn === 'function'
- _.size(obj) → Object.keys(obj).length
- _.each(arr, fn) → arr.forEach(fn)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Replace spin (2013, unmaintained) with a CSS-only spinner:
  28px border-based circle with @Keyframes rotation, injected once
- Replace lru (uses Node 'events' module) with inline js/lru.js:
  25-line Map-based LRU cache with get/set/eviction
- Remove events polyfill (no longer needed without lru)
- Fix leftover _.mapObject call in hide_spinner

Dependencies dropped: spin, lru, events (3 packages removed)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Remove polyfills targeting IE/ancient browsers (now targeting ES2018+):
- ArrayBuffer.prototype.slice (iOS/old Firefox)
- ArrayBuffer.isView
- requestAnimFrame/cancelAnimFrame shims → native requestAnimationFrame
- Float64Array polyfill (iOS)
- String.prototype.endsWith (ES6)
- TypedArray.prototype.slice (6 types)
- Array.isArray
- console shim
- Firefox 4 subarray bug workaround
- addWheelListener (mousewheel/DOMMouseScroll) → native 'wheel' event
- Proxy polyfill
- mozDash/webkitLineDash fallbacks in dashOn/dashOff → setLineDash only
- window.event/attachEvent fallbacks

Kept: ArrayBuffer.transfer polyfill (not yet universal),
dashOn/dashOff, getKeyCode, setKeypressHandler, update, debounce, uuidv4.

common.js: 393 lines → 100 lines

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Configure @vitest/coverage-v8 with text, lcov, and html reporters
- Add npm script: test:coverage

New test files:
- lru.test.js: 8 tests — eviction, recency refresh, overwrite, edge cases (100% coverage)
- common.test.js: 11 tests — dashOn/Off, getKeyCode, update, debounce, uuidv4
- m.math.test.js: 20 tests — vmov, vmovmax, vmxmn, vsmul, vfill, vabs,
  cvmag, cvmag2, PointArray, throttle

Total: 8 test files, 71 passing, 8 skipped
Coverage: lru.js 100%, common.js 82% (+29), m.js 62% (+7)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
New test files:
- m.extended.test.js (84 tests): log10, vlog10, vlogscale, cvmag2logscale,
  cvpha, cvphad, trunc, sign, bound, mult_prefix, trim_name, epoch
  conversion round-trips, pad
- ColorMap.extended.test.js (21 tests): construction, setRange,
  getColorIndex, getColorByIndex, getNColors, interpolation, edge cases
- sigplot.plugin.test.js (23 tests): Plugin lifecycle, init/dispose,
  addListener/removeListener, menu/refresh hooks, properties

Coverage improvements:
  m.js:              62% → 80% stmts, 42% → 64% branch, 61% → 85% funcs
  ColorMap.js:       75% → 81% stmts
  sigplot.plugin.js: 42% → 84% stmts, 42% → 100% funcs

Total: 11 files, 199 passing, 8 skipped

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Mock clientWidth/clientHeight on the container element to return
dimensions based on style.width/height (accounting for display:none).
This lets the 5 previously-skipped tests pass in jsdom without a
real browser layout engine.

Remaining 3 skipped: XHR-based tests (overlay_href needs file loading)

Tests: 204 passing, 3 skipped (was 199 passing, 8 skipped)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Vitest browser mode requires server-side preprocessing of setup files,
but sigfile's UMD wrapper references 'window' at top level, causing
failures in Node context. Until sigfile ships proper ESM exports,
jsdom with canvas context stubs is the correct approach.

The canvas stubs are sufficient for testing data structures, API surface,
math operations, and plot construction logic — which is what matters for
unit tests. Visual rendering is covered by the interactive test suite.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Install typescript, @typescript-eslint/parser, @typescript-eslint/eslint-plugin, @types/tinycolor2
- Create tsconfig.json with strict mode, allowJs for incremental migration
- Update ESLint config with TypeScript parser and plugin
- Update esbuild entrypoints for .ts files
- Add typecheck and types npm scripts

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Convert all 20 source files from JavaScript to TypeScript:
- Create js/types.ts with shared interfaces (BlueHeader, MxContext, GxContext,
  PlotSettings, LayerOptions, and supporting types)
- Create js/sigfile.d.ts declaration stub for sigfile dependency
- Migrate core: sigplot.ts (9300 lines), mx.ts (5900 lines), m.ts (1300 lines)
- Migrate layers: layer1d.ts, layer2d.ts, layer1dSDS.ts, layer2dSDS.ts
- Migrate plugins: plugin.ts, accordion.ts, annotations.ts, boxes.ts,
  playback.ts, slider.ts, plugins.ts (barrel)
- Migrate utilities: common.ts, ColorMap.ts, CanvasInput.ts, lru.ts, license.ts
- Migrate dommenu: mx.dommenu.ts
- Use namespace import for sigfile (import * as sigfile)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Enable noImplicitAny, then full strict: true in tsconfig.json
- Remove @ts-nocheck from all 10 files (677 type errors fixed):
  sigplot.ts, mx.ts, layer1d.ts, layer2d.ts, layer1dSDS.ts,
  layer2dSDS.ts, CanvasInput.ts, accordion.ts, annotations.ts, boxes.ts
- Replace 32 any types with concrete types in types.ts
- Tighten types in m.ts and sigplot.plugin.ts

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Fixes found by parallel review with Gemini 3 Pro, GPT 5.3, and Opus 4.6:

Pass 1 (3 critical, 2 medium):
- Fix layer2d: use dview.length not .byteLength (was 4-8x wrong)
- Fix CanvasInput: check data==='none' not _boxShadow state for shadow init
- Fix all layers: revert hcb.buf._type back to hcb.buf_type
- Fix add_highlight: restore array-replaces-all behavior
- Fix MxContext.xi type: boolean → boolean | string

Pass 2 (1 critical, 3 high, 3 medium):
- Fix Layer1D: use position=0 not undefined (null coerces to 0 in arithmetic)
- Fix Layer2D: remove spurious position/ymin/ymax from constructor
- Fix slider: restore .bind() listener references for proper removal
- Fix slider: restore && (intersection) for 'both' mode hit-testing
- Fix slider: restore evt.slider_drag guard and preventDefault calls
- Fix m.ts: getDview returns TypedArray|undefined to preserve null guards
- Fix hide_spinner: guard HCB_UCB against undefined
- Fix esbuild: unwrap default export in IIFE for global sigplot access

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add 25 regression tests covering all 12 bugs found in code review
- Distribute tests into per-module files: slider.test.ts, m.extended.test.ts,
  tests.sigplot.test.ts, canvasinput.test.ts
- Migrate all 12 test files from .test.js to .test.ts
- Generate .d.ts declaration files in dist/types/
- Update package.json with types field and exports map

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Update Vite alias to point to sigplot.ts
- Add Vite middleware to serve dist/sigplot.js for examples
- Set willReadFrequently on main canvas context for performance
- Add trailing slashes to example links for index.html resolution
- Run prettier on all TS files
- Disable no-undef and no-redeclare in ESLint for .ts files

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant