diff --git a/.github/workflows/js.yml b/.github/workflows/js.yml index f85241a..a129ad1 100644 --- a/.github/workflows/js.yml +++ b/.github/workflows/js.yml @@ -174,6 +174,11 @@ jobs: with: node-version: ${{ matrix.node-version }} + - name: Install dependencies (Node) + if: matrix.runtime == 'node' + working-directory: js + run: npm ci + - name: Test Node.js compatibility if: matrix.runtime == 'node' run: | @@ -185,6 +190,7 @@ jobs: process.exit(1); }); " + node --test js/tests/node-terminal-artifacts.mjs release: name: Release JavaScript package diff --git a/js/.changeset/fuzzy-gifs-wave.md b/js/.changeset/fuzzy-gifs-wave.md new file mode 100644 index 0000000..4fdf904 --- /dev/null +++ b/js/.changeset/fuzzy-gifs-wave.md @@ -0,0 +1,6 @@ +--- +'command-stream': patch +--- + +Fix GIF terminal artifact rendering on Node.js by supporting the CommonJS +default export exposed by `gifenc`. diff --git a/js/src/terminal-artifacts.mjs b/js/src/terminal-artifacts.mjs index 6d2624b..d6f3dcc 100644 --- a/js/src/terminal-artifacts.mjs +++ b/js/src/terminal-artifacts.mjs @@ -407,9 +407,12 @@ const renderRecordingSvg = ({ frames, options, font }) => { }; const renderGif = async ({ frames, options, font }) => { - const [{ Resvg }, { GIFEncoder, applyPalette, quantize }] = await Promise.all( - [import('@resvg/resvg-js'), import('gifenc')] - ); + const [{ Resvg }, gifencModule] = await Promise.all([ + import('@resvg/resvg-js'), + import('gifenc'), + ]); + const gifenc = gifencModule.GIFEncoder ? gifencModule : gifencModule.default; + const { GIFEncoder, applyPalette, quantize } = gifenc; const { width, height } = dimensions(frames, options); const { times } = frameTimes(frames, options.idleTimeLimit); const sheet = svgShell({ diff --git a/js/tests/node-terminal-artifacts.mjs b/js/tests/node-terminal-artifacts.mjs new file mode 100644 index 0000000..fcb79db --- /dev/null +++ b/js/tests/node-terminal-artifacts.mjs @@ -0,0 +1,33 @@ +import assert from 'node:assert/strict'; +import { mkdtemp, readFile, rm } from 'node:fs/promises'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; +import { test } from 'node:test'; + +import { writeTerminalArtifacts } from '../src/terminal-artifacts.mjs'; + +test('writes GIF terminal artifacts in Node.js', async (context) => { + const directory = await mkdtemp(join(tmpdir(), 'command-stream-node-gif-')); + context.after(() => rm(directory, { force: true, recursive: true })); + + await writeTerminalArtifacts({ + directory, + frames: [ + { + time: 0, + cols: 1, + rows: 1, + lines: [''], + cells: [[]], + }, + ], + transcript: '', + asciicast: { + header: { version: 2, width: 1, height: 1, timestamp: 0, env: {} }, + events: [], + }, + }); + + const gif = await readFile(join(directory, 'recording.gif')); + assert.equal(gif.subarray(0, 6).toString(), 'GIF89a'); +});