Skip to content
citycafe578Public

About

An adaptive, URL-safe string compression library that auto-selects the shortest encoding (RLE, Huffman, LZ77, MIX & JSON optimizer).

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Latest commit

 

History

12 Commits

Folders and files

Repository files navigation

ZipURL

ZipURL is a lightweight JavaScript text compression library that automatically selects the shortest representation from multiple compression strategies.

Instead of relying on a single compression algorithm, ZipURL tries several encoders, compares the resulting string lengths, and stores the shortest result together with a compact two-character algorithm identifier.

Features

  • Multiple compression algorithms in one library
  • Automatic selection of the shortest encoded result
  • Support for ordinary text
  • Specialized JSON compression
  • Hybrid compression pipelines
  • Prefix preservation
  • Simple compress() / decompress() API
  • ES module support
  • No runtime dependencies

Supported Compression Methods

ID Method Description
RW Raw Original uncompressed text
RL RLE Run-Length Encoding
HF Huffman Frequency-based variable-length coding
LZ LZ77 Sliding-window dictionary compression
MX Huffman + LZ77 LZ77 followed by Huffman coding
JP JSON JSON key deduplication and structural packing
JH JSON + Huffman JSON packing followed by Huffman
JL JSON + LZ77 JSON packing followed by LZ77
JM JSON + Huffman + LZ77 JSON packing followed by the hybrid compressor

For every input, ZipURL generates the applicable representations and selects the one with the smallest data.length.

How It Works

The main compress() function follows this process:

Input
  │
  ├── Raw
  ├── RLE
  ├── Huffman
  ├── LZ77
  ├── Huffman + LZ77
  │
  └── If input is valid JSON
        ├── JSON packing
        ├── JSON + Huffman
        ├── JSON + LZ77
        └── JSON + Huffman + LZ77
                 │
                 ▼
        Compare encoded lengths
                 │
                 ▼
          Select shortest
                 │
                 ▼
        Add 2-character ID
                 │
                 ▼
             Output

The selected compression method is stored as a two-character prefix, allowing decompress() to determine which decoder should be used.

Installation

ZipURL has no runtime dependencies. The package includes tsup, typescript, and vitest as development dependencies.

Option 1: Install from npm

npm install zipurl

Then import the package:

import { compress, decompress } from "zipurl";

Option 2: Install directly from GitHub

You can install the package directly from the GitHub repository without publishing it to the npm Registry:

npm install github:citycafe578/ZipURL

The package name remains zipurl, so the import is the same:

import { compress, decompress } from "zipurl";

The repository must include the generated dist/ directory for this installation method. Before pushing changes, run:

npm run build
git add dist
git commit -m "build library"
git push

Option 3: Use from a browser with a CDN

The browser bundle is available from jsDelivr after dist/index.global.js has been pushed to GitHub:

<!-- Load the library from GitHub through jsDelivr -->
<script src="https://cdn.jsdelivr.net/gh/citycafe578/ZipURL@main/dist/index.global.js"></script>

<script>
        const compressed = ZipURL.compress("Hello World!");
        console.log("Compressed:", compressed);
        console.log("Decompressed:", ZipURL.decompress(compressed));
</script>

The global browser bundle exposes the ZipURL object with compress() and decompress() methods.

Option 4: Use an ES module URL in the browser

Native browser ES modules can import the ESM build directly:

<script type="module">
        import { compress, decompress } from "https://cdn.jsdelivr.net/gh/citycafe578/ZipURL@main/dist/index.js";

        const compressed = compress("Hello World!");
        console.log("Compressed:", compressed);
        console.log("Decompressed:", decompress(compressed));
</script>

For Vue, React, or Vite projects, installing from npm or GitHub is generally the more reliable option because the bundler can resolve the package normally.

Basic Usage

Compress

import { compress } from "zipurl";

const text = "AAAAABBBBBCCCCCCCCCCCC";

const compressed = compress(text);

console.log(compressed);

Decompress

import { decompress } from "zipurl";

const restored = decompress(compressed);

console.log(restored);

The following property should hold for valid inputs:

decompress(compress(text)) === text

Prefix Support

compress() accepts an optional prefix argument.

const compressed = compress("hello world", "https://example.com/");

When a prefix is supplied, ZipURL stores it separately from the compressed payload:

P<prefix length>:<prefix><compression ID><compressed data>

For example, the structure is conceptually:

P20:https://example.com/...

During decompression, ZipURL removes the stored prefix before decoding the payload.

This makes it possible to preserve a URL-like prefix while still compressing the remaining content.

Compression Algorithms

RLE

Run-Length Encoding replaces consecutive identical characters with a count and the character.

Example:

AAAAABB

becomes conceptually:

5#A2#B

RLE is especially useful when the input contains long runs of repeated characters.

Huffman Coding

ZipURL builds a frequency map for the input and constructs a Huffman tree.

The resulting character-to-bit mapping is stored together with the packed bit stream.

The encoded representation contains:

<bit length>;<JSON code table>|<packed data>

The bit stream is packed into bytes before being converted into a compact string representation.

LZ77

The LZ77 implementation uses a sliding window and searches previous input for the longest matching sequence.

The default parameters are:

windowSize = 255
minMatch = 3

The hybrid compressor uses:

windowSize = 4096
minMatch = 4

Matches are represented using:

(offset,length)

A special (0,1) representation is used when the literal character itself is (.

Huffman + LZ77

The hybrid compressor first applies LZ77 and then Huffman coding:

Huffman.encode(LZ77.encode(text, 4096, 4))

Decompression reverses the order:

LZ77.decode(Huffman.decode(compressedText))

JSON Compression

ZipURL has a specialized JSON packer that attempts to reduce structural redundancy before applying the normal compressors.

For objects, property names are stored once in a shared key list and replaced by numeric indexes.

For arrays containing multiple objects, common keys can be represented as a column-like structure:

[
    keyList,
    packedData
]

This is particularly useful for JSON containing many objects with repeated property names.

JSON Compression Pipeline

For valid JSON, ZipURL tests:

JSON packing
JSON + Huffman
JSON + LZ77
JSON + Huffman + LZ77

The shortest result is selected together with the corresponding ID.

If the input is not valid JSON, these JSON-specific candidates are simply skipped.

Output Format

A normal compressed result has the following structure:

<ID><data>

where <ID> is one of:

RW
RL
HF
LZ
MX
JP
JH
JL
JM

For example:

HF<encoded data>

The first two characters tell decompress() which decoding pipeline should be used.

Prefix Format

When a prefix is provided:

P<prefix length>:<prefix><ID><data>

This allows the decompressor to recover the prefix and then decode the compressed payload.

API

compress(text, prefix = "")

Compresses the supplied text and automatically selects the shortest supported representation.

const result = compress(text);

Parameters:

Parameter Type Default Description
text string — Text to compress
prefix string "" Optional prefix preserved outside the compressed payload

Returns:

string

If text is empty or falsy, an empty string is returned.

decompress(compressedText)

Restores the original text.

const text = decompress(compressedText);

Parameters:

Parameter Type Description
compressedText string Output generated by compress()

Returns:

string

Design Philosophy

ZipURL does not assume that one compression algorithm is always optimal.

Different data patterns favor different approaches:

Repeated characters       → RLE
Frequency-heavy text      → Huffman
Repeated substrings       → LZ77
Mixed redundancy          → Huffman + LZ77
Structured JSON           → JSON packing
JSON + repeated patterns  → JSON + compression

Therefore, ZipURL treats compression as a selection problem:

Generate candidates
        ↓
Measure encoded length
        ↓
Choose shortest representation
        ↓
Store algorithm ID

This approach prioritizes practical output size over committing to a single compression technique.

Project Structure

The library source and package files are organized as follows:

src/
├── index.js       # Library entry point and compression implementation
└── index.d.ts     # Public TypeScript declarations
scripts/
└── copy-types.mjs # Copies declarations into dist during build
test/
└── library.test.js
dist/              # Generated build output, committed for CDN/GitHub installs

Important Notes

  • The current implementation compares candidates using JavaScript string .length, so the selection criterion is encoded string length rather than a formal byte-level storage measurement.
  • Huffman output contains its code table as part of the encoded representation.
  • JSON compression is only attempted when the input can be parsed successfully by JSON.parse().
  • Compression does not guarantee that the result will be shorter than the original input. The raw representation (RW) is included so that the shortest candidate can still be selected.
  • This project is intended as a lightweight JavaScript compression experiment rather than a replacement for established binary compression formats such as gzip, Brotli, or Zstandard.

Example

import { compress, decompress } from "zipurl";

const original = JSON.stringify([
    { name: "Alice", age: 20, city: "Taipei" },
    { name: "Bob", age: 21, city: "Taipei" },
    { name: "Charlie", age: 22, city: "Taipei" }
]);

const compressed = compress(original);
const restored = decompress(compressed);

console.log("Original :", original.length);
console.log("Compressed:", compressed.length);
console.log("Restored :", restored);
console.log("Valid    :", restored === original);

License

The package metadata declares the MIT license. Add a LICENSE file containing the MIT license text before publishing publicly.

About

An adaptive, URL-safe string compression library that auto-selects the shortest encoding (RLE, Huffman, LZ77, MIX & JSON optimizer).

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages