'use strict'; const assert = require('node:assert/strict'); const fs = require('node:fs'); const vm = require('node:vm'); const viewer = fs.readFileSync('viewer/spine.html', 'utf8'); const releaseViewer = fs.readFileSync('release/UNIVERSAL_SpineViewer/viewer/spine.html', 'utf8'); const server = fs.readFileSync('SpineThumbnailGenerateServer/js/renderer.js', 'utf8'); function functionSource(source, name) { const start = source.indexOf(`function ${name}(`); assert.ok(start >= 0, `missing ${name}`); const open = source.indexOf('{', start); let depth = 0; for (let index = open; index < source.length; index++) { if (source[index] === '{') depth++; else if (source[index] === '}' && --depth === 0) return source.slice(start, index + 1); } throw new Error(`unterminated ${name}`); } const calls = []; const skeleton = { update(delta) { calls.push(['time', delta]); }, updateWorldTransform(mode) { calls.push(['world', mode]); }, }; vm.runInNewContext(`const spine = { Physics: { update: 'update', reset: 'reset' } }; ${functionSource(viewer, 'updateWorld')}; updateWorld(skeleton, 0.05); updateWorld(skeleton, 0, true);`, { skeleton, calls }); assert.deepEqual(calls, [['time', 0.05], ['world', 'update'], ['world', 'reset']]); assert.equal(viewer, releaseViewer, 'release viewer must mirror the source viewer'); assert.match(viewer, /MAX_FRAME_DELTA = 0\.064[\s\S]*updateWorld\(skeleton, frameDelta\)/); assert.match(viewer, /time - previousTime[\s\S]*previousTime === undefined/); assert.match(server, /skeleton\.update\(delta\)[\s\S]*spine\.Physics\.reset/); assert.match(server, /time - previousTime[\s\S]*previousTime === undefined/); console.log('PASS: Spine 4.2+ physics advances time and resets between sampling passes');