npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

savfilewriter

v1.0.0

Published

A pure JavaScript library for writing SPSS .sav (system) files in the browser or Node.js

Downloads

592

Readme

savwriter

A pure JavaScript library for writing SPSS .sav (system) files in the browser or Node.js.

Overview

savwriter creates uncompressed SPSS .sav files from metadata and data records. It's designed to work seamlessly with data parsed by sav-reader or similar libraries, enabling full round-trip support for SPSS data files.

Features

Write valid .sav files compatible with SPSS Statistics and PSPP ✅ Numeric variables with custom formats (F8.2, COMMA10.2, etc.) ✅ String variables up to 255 bytes (short strings) ✅ Value labels for categorical data ✅ Variable labels with UTF-8 support ✅ Long variable names (>8 characters) ✅ Missing values (SYSMIS for numeric, empty for string) ✅ Uncompressed format (compression=0) ✅ Browser downloads via built-in download() method ✅ Pure JavaScript - no dependencies, works in browsers and Node.js

Installation

// ES6 import
import { SavWriter } from './savwriter/index.js';

Quick Start

// Define your data structure
const metadata = {
    encoding: 'UTF-8',
    fileLabel: 'My Survey Data',
    sysvars: [
        {
            name: 'id',
            type: 0,  // 0 = numeric
            label: 'Respondent ID'
        },
        {
            name: 'age',
            type: 0,
            label: 'Age in years',
            printFormat: 'F3.0'
        },
        {
            name: 'gender',
            type: 0,
            label: 'Gender',
            values: {
                '1': 'Male',
                '2': 'Female',
                '3': 'Other'
            }
        },
        {
            name: 'name',
            type: 50,  // String width in bytes
            label: 'Full Name'
        }
    ]
};

// Your data records
const records = [
    { id: 1, age: 28, gender: 1, name: 'John Smith' },
    { id: 2, age: 35, gender: 2, name: 'Jane Doe' },
    { id: 3, age: 42, gender: 1, name: 'Bob Johnson' }
];

// Write to ArrayBuffer
const buffer = SavWriter.write(metadata, records);

// Or download directly in browser
SavWriter.download(metadata, records, 'output.sav');

API Reference

SavWriter.write(metadata, records, options)

Writes a complete .sav file to an ArrayBuffer.

Parameters:

  • metadata (Object): File and variable metadata
    • encoding (String): Character encoding (default: 'UTF-8')
    • fileLabel (String): Optional file description
    • sysvars (Array): Variable definitions
  • records (Array): Data records as objects with variable names as keys
  • options (Object): Optional settings
    • product (String): Product identification string
    • compression (Number): Compression type (0 = none, default)

Returns: ArrayBuffer - Binary .sav file data

Example:

const buffer = SavWriter.write(metadata, records, {
    fileLabel: 'Custom Dataset'
});

SavWriter.download(metadata, records, filename, options)

Writes and downloads a .sav file in the browser.

Parameters:

  • metadata (Object): File and variable metadata
  • records (Array): Data records
  • filename (String): Download filename
  • options (Object): Optional settings (same as write())

Example:

SavWriter.download(metadata, records, 'survey-results.sav');

Variable Definition

Each variable in metadata.sysvars should have:

{
    name: 'variable_name',      // Required: Variable name (any length)
    type: 0,                    // Required: 0=numeric, or string width
    label: 'Description',       // Optional: Descriptive label
    printFormat: 'F8.2',        // Optional: Display format
    writeFormat: 'F8.2',        // Optional: Write format
    values: {                   // Optional: Value labels
        '1': 'Label 1',
        '2': 'Label 2'
    }
}

Variable Types

  • Numeric: type: 0

    • Stored as 64-bit float (IEEE 754)
    • Missing values represented as SYSMIS (-DBL_MAX)
  • String: type: N where N is the width in bytes

    • Maximum width: 255 bytes (short strings)
    • Padded with spaces if value is shorter than width
    • Empty/null values stored as spaces

Format Specifications

Formats can be specified as strings:

  • 'F8.2' - Standard numeric (8 chars wide, 2 decimals)
  • 'F10.0' - Integer display
  • 'COMMA10.2' - Number with comma separators
  • 'DOLLAR12.2' - Dollar amount
  • 'DATE11' - Date format
  • 'A50' - String (50 characters)

Common format types:

  • F - Standard numeric
  • COMMA - Number with commas
  • DOLLAR - Currency
  • PCT - Percentage
  • DATE - Date
  • TIME - Time
  • A - String

Data Records

Data records are plain JavaScript objects:

const records = [
    {
        id: 1,
        age: 28,
        gender: 1,
        name: 'John Smith',
        income: 50000.00
    },
    {
        id: 2,
        age: 35,
        gender: 2,
        name: 'Jane Doe',
        income: 65000.00
    }
];

Missing Values:

  • Numeric: Use null, undefined, empty string, or NaN
  • String: Use null, undefined, or empty string

Complete Example

import { SavWriter } from './savwriter/index.js';

// Survey data with mixed types
const metadata = {
    encoding: 'UTF-8',
    fileLabel: 'Customer Satisfaction Survey 2025',
    sysvars: [
        {
            name: 'respondent_id',
            type: 0,
            label: 'Respondent ID',
            printFormat: 'F8.0'
        },
        {
            name: 'age',
            type: 0,
            label: 'Age in years',
            printFormat: 'F3.0'
        },
        {
            name: 'satisfaction',
            type: 0,
            label: 'Overall Satisfaction',
            values: {
                '1': 'Very Dissatisfied',
                '2': 'Dissatisfied',
                '3': 'Neutral',
                '4': 'Satisfied',
                '5': 'Very Satisfied'
            }
        },
        {
            name: 'fullname',
            type: 50,
            label: 'Full Name'
        },
        {
            name: 'comments',
            type: 200,
            label: 'Additional Comments'
        }
    ]
};

const records = [
    {
        respondent_id: 1,
        age: 28,
        satisfaction: 5,
        fullname: 'John Smith',
        comments: 'Excellent service!'
    },
    {
        respondent_id: 2,
        age: 35,
        satisfaction: 4,
        fullname: 'Jane Doe',
        comments: 'Very happy with the product.'
    },
    {
        respondent_id: 3,
        age: null,  // Missing value
        satisfaction: 3,
        fullname: 'Bob Johnson',
        comments: ''
    }
];

// Create and download
SavWriter.download(metadata, records, 'survey-results.sav');

File Structure

The library writes .sav files with the following structure:

  1. File Header Record (176 bytes)

    • Magic string ($FL2)
    • Product identification
    • File metadata (cases, variables, encoding)
  2. Variable Records (Type 2)

    • One record per variable
    • Continuation records for long strings
  3. Value Label Records (Types 3 & 4)

    • Type 3: Value-to-label mappings
    • Type 4: Variables using those labels
  4. Extension Records (Type 7)

    • Character Encoding (Subtype 20)
    • Long Variable Names (Subtype 13)
  5. Dictionary Termination (rec_type = 999)

  6. Data Records

    • Uncompressed binary data
    • One record per case

Testing

Open the example file in a browser to see a comprehensive demonstration:

  • example_complex_dataset.html - End-to-end integration test with complex data

Additional unit tests are available in the test_files/ directory:

  • test_files/test-binarywriter.html - Low-level binary writing tests
  • test_files/test-headerwriter.html - File header tests
  • test_files/test-variablewriter.html - Variable record tests
  • test_files/test-valuelabelwriter.html - Value label tests

The complex example includes a "Download Sample File" button to generate a test .sav file.

Limitations (MVP)

  • ✅ Uncompressed files only (compression=0)
  • ✅ Short strings only (≤255 bytes)
  • ❌ No compression support (bytecode or ZLIB)
  • ❌ No very long strings (>255 bytes)
  • ❌ No missing value specifications (beyond SYSMIS)
  • ❌ No document records
  • ❌ Limited extension records

Compatibility

  • SPSS Statistics (all versions) - ✅ Tested
  • PSPP - ✅ Compatible
  • R (haven package) - ✅ Compatible
  • Python (pyreadstat) - ✅ Compatible

Technical Details

  • Endianness: Little-endian (layout_code = 2)
  • Encoding: UTF-8 by default
  • Missing numeric: -DBL_MAX (-1.7976931348623157e+308)
  • String padding: Spaces (0x20)
  • Alignment: Variable labels padded to 4-byte boundary, value labels to 8-byte

Use Cases

  • Export filtered/modified datasets from SavQuick
  • Generate .sav files from survey responses
  • Convert CSV/JSON to SPSS format
  • Create synthetic test datasets
  • Round-trip SPSS data (read with sav-reader, write with savwriter)

Architecture

savwriter/
├── index.js              # Public API
├── BinaryWriter.js       # Low-level binary writing
├── SavWriter.js          # High-level orchestration
├── writers/
│   ├── HeaderWriter.js   # File header (176 bytes)
│   ├── VariableWriter.js # Variable metadata
│   ├── ValueLabelWriter.js # Value labels (Types 3 & 4)
│   ├── ExtensionWriter.js  # Extension records (Type 7)
│   └── DataWriter.js     # Data records
└── utils/
    └── FormatEncoder.js  # Print/write format encoding

Contributing

This library was created as part of SavQuick project. Future enhancements:

  • Compression support (bytecode, ZLIB)
  • Very long strings (>255 bytes)
  • Missing value specifications
  • Document records
  • Additional extension records

References

  • PSPP System File Format Specification
  • SPSS Statistics File Format Documentation
  • IEEE 754 Floating Point Standard

License

Part of the SavQuick project.

Version

1.0.0 - Initial release with uncompressed file support