Sorry, the diff of this file is not supported yet
+253
-16
@@ -56,4 +56,11 @@ /* | ||
| workerLimit?: number, | ||
| JSONstring?: boolean, | ||
| debug?: boolean | ||
| } | ||
| /** | ||
| * JavaScript String Compressor - decompress options | ||
| * @license MIT | ||
| * @copyright (c) 2025-2026 JustDeveloper <<https://justdeveloper.is-a.dev>> | ||
| * @since 2.1.0 | ||
| */ | ||
| export interface decompressOptions { | ||
@@ -63,2 +70,39 @@ stringify?: boolean, | ||
| } | ||
| /** | ||
| * JavaScript String Compressor - debug output | ||
| * @license MIT | ||
| * @copyright (c) 2025-2026 JustDeveloper <<https://justdeveloper.is-a.dev>> | ||
| * @since 2.1.0 | ||
| */ | ||
| export interface JSSCCompressedDebug { | ||
| string: string, | ||
| header: { | ||
| code: number, | ||
| bin: string, | ||
| blocks: [string, "0"|"1", string, "0"|"1", "0"|"1", "0"|"1", string], | ||
| code1: string, | ||
| code2: string, | ||
| code3: string, | ||
| s: boolean, | ||
| i: boolean, | ||
| o: boolean, | ||
| b: boolean | ||
| }, | ||
| mode: { | ||
| id: number, | ||
| name: string | ||
| } | ||
| } | ||
| /** | ||
| * JavaScript String Compressor - debug output | ||
| * @license MIT | ||
| * @copyright (c) 2025-2026 JustDeveloper <<https://justdeveloper.is-a.dev>> | ||
| * @since 2.1.0 | ||
| */ | ||
| export interface JSSCDebug { | ||
| input: string|object|number|JSSCCompressedDebug, | ||
| output: string|object|number|JSSCCompressedDebug, | ||
| options: compressOptions | decompressOptions, | ||
| workers: boolean | ||
| } | ||
@@ -73,3 +117,3 @@ /** | ||
| */ | ||
| export function compress(str: string, options?: compressOptions): Promise<string>; | ||
| export function compress(str: string, options?: compressOptions): Promise<string|JSSCDebug>; | ||
| /** | ||
@@ -84,3 +128,3 @@ * JavaScript String Compressor - compress function | ||
| */ | ||
| export function compress(obj: object, options?: compressOptions): Promise<string>; | ||
| export function compress(obj: object, options?: compressOptions): Promise<string|JSSCDebug>; | ||
| /** | ||
@@ -94,3 +138,3 @@ * JavaScript String Compressor - compress function | ||
| */ | ||
| export function compress(int: number, options?: compressOptions): Promise<string>; | ||
| export function compress(int: number, options?: compressOptions): Promise<string|JSSCDebug>; | ||
@@ -105,3 +149,3 @@ /** | ||
| */ | ||
| export function decompress(str: string): Promise<object|number|string>; | ||
| export function decompress(str: string): Promise<object|number|string|JSSCDebug>; | ||
| /** | ||
@@ -116,3 +160,3 @@ * JavaScript String Compressor - decompress function | ||
| */ | ||
| export function decompress(str: string, stringify: true): Promise<string>; | ||
| export function decompress(str: string, stringify: true): Promise<string|JSSCDebug>; | ||
| /** | ||
@@ -123,6 +167,6 @@ * JavaScript String Compressor - decompress function | ||
| * @example | ||
| * await decompress(compressedString, true); | ||
| * await decompress(compressedString); | ||
| * @since 2.1.0 | ||
| */ | ||
| export function decompress(str: string, options?: decompressOptions): Promise<object|number|string>; | ||
| export function decompress(str: string, options?: decompressOptions): Promise<object|number|string|JSSCDebug>; | ||
@@ -132,3 +176,3 @@ /** | ||
| * | ||
| * Compresses strings, integers and objects into non-standard Base64 strings | ||
| * Compresses strings, integers and objects into non-standard Base64 strings (`0-9` `a-z` `A-Z` `+` `/`) | ||
| * @param str - Input string to compress | ||
@@ -144,3 +188,3 @@ * @returns Compressed string in non-standard Base64 format | ||
| * | ||
| * Compresses strings, integers and objects into non-standard Base64 strings | ||
| * Compresses strings, integers and objects into non-standard Base64 strings (`0-9` `a-z` `A-Z` `+` `/`) | ||
| * @param obj - Input object to compress | ||
@@ -157,3 +201,3 @@ * > **Note: it will `JSON.stringify()` your object so it may lose some data if your object has getters/setters/non-enumerables/etc.!** | ||
| * | ||
| * Compresses strings, integers and objects into non-standard Base64 strings | ||
| * Compresses strings, integers and objects into non-standard Base64 strings (`0-9` `a-z` `A-Z` `+` `/`) | ||
| * @param int - Input integer to compress | ||
@@ -168,2 +212,72 @@ * @returns Compressed string in non-standard Base64 format | ||
| /** | ||
| * JavaScript String Compressor - compressToBase64URL function | ||
| * | ||
| * Compresses strings, integers and objects into non-standard Base64URL strings (`0-9` `a-z` `A-Z` `-` `_`) | ||
| * @param str - Input string to compress | ||
| * @returns Compressed string in non-standard Base64URL format | ||
| * @example | ||
| * await compressToBase64URL('Hello, World!'); | ||
| * @since 2.1.0 | ||
| */ | ||
| export function compressToBase64URL(str: string, options?: compressOptions): Promise<string>; | ||
| /** | ||
| * JavaScript String Compressor - compressToBase64URL function | ||
| * | ||
| * Compresses strings, integers and objects into non-standard Base64URL strings (`0-9` `a-z` `A-Z` `-` `_`) | ||
| * @param obj - Input object to compress | ||
| * > **Note: it will `JSON.stringify()` your object so it may lose some data if your object has getters/setters/non-enumerables/etc.!** | ||
| * @returns Compressed string in non-standard Base64URL format | ||
| * @example | ||
| * await compressToBase64URL({a: "b"}); | ||
| * @since 2.1.0 | ||
| */ | ||
| export function compressToBase64URL(obj: string, options?: compressOptions): Promise<string>; | ||
| /** | ||
| * JavaScript String Compressor - compressToBase64URL function | ||
| * | ||
| * Compresses strings, integers and objects into non-standard Base64URL strings (`0-9` `a-z` `A-Z` `-` `_`) | ||
| * @param int - Input integer to compress | ||
| * @returns Compressed string in non-standard Base64URL format | ||
| * @example | ||
| * await compressToBase64URL(10); | ||
| * @since 2.1.0 | ||
| */ | ||
| export function compressToBase64URL(int: string, options?: compressOptions): Promise<string>; | ||
| /** | ||
| * JavaScript String Compressor - compressToUint8Array function | ||
| * | ||
| * Compresses strings, integers and objects into Uint8Arrays | ||
| * @param str - Input string to compress | ||
| * @returns Compressed Uint8Array | ||
| * @example | ||
| * await compressToUint8Array('Hello, World!'); | ||
| * @since 2.1.0 | ||
| */ | ||
| export function compressToUint8Array(str: string, options?: compressOptions): Promise<Uint8Array<ArrayBuffer>>; | ||
| /** | ||
| * JavaScript String Compressor - compressToUint8Array function | ||
| * | ||
| * Compresses strings, integers and objects into Uint8Arrays | ||
| * @param obj - Input object to compress | ||
| * > **Note: it will `JSON.stringify()` your object so it may lose some data if your object has getters/setters/non-enumerables/etc.!** | ||
| * @returns Compressed Uint8Array | ||
| * @example | ||
| * await compressToUint8Array({a: "b"}); | ||
| * @since 2.1.0 | ||
| */ | ||
| export function compressToUint8Array(obj: string, options?: compressOptions): Promise<Uint8Array<ArrayBuffer>>; | ||
| /** | ||
| * JavaScript String Compressor - compressToUint8Array function | ||
| * | ||
| * Compresses strings, integers and objects into Uint8Arrays | ||
| * @param int - Input integer to compress | ||
| * @returns Compressed Uint8Array | ||
| * @example | ||
| * await compressToUint8Array(10); | ||
| * @since 2.1.0 | ||
| */ | ||
| export function compressToUint8Array(int: string, options?: compressOptions): Promise<Uint8Array<ArrayBuffer>>; | ||
| /** | ||
| * JavaScript String Compressor - compressLarge function | ||
@@ -183,3 +297,3 @@ * | ||
| * | ||
| * Compresses large strings (`str.length > 1024`) into non-standard Base64 strings | ||
| * Compresses large strings (`str.length > 1024`) into non-standard Base64 strings (`0-9` `a-z` `A-Z` `+` `/`) | ||
| * @param str - Input string to compress | ||
@@ -194,4 +308,28 @@ * @returns Compressed string in non-standard Base64 format | ||
| /** | ||
| * JavaScript String Compressor - compressLargeToBase64URL function | ||
| * | ||
| * Compresses large strings (`str.length > 1024`) into non-standard Base64URL strings (`0-9` `a-z` `A-Z` `-` `_`) | ||
| * @param str - Input string to compress | ||
| * @returns Compressed string in non-standard Base64URL format | ||
| * @example | ||
| * await compressLargeToBase64URL('Hello, World!'); | ||
| * @since 2.1.0 | ||
| */ | ||
| export function compressLargeToBase64URL(str: string, options?: compressOptions): Promise<string>; | ||
| /** | ||
| * JavaScript String Compressor - compressLargeToUint8Array function | ||
| * | ||
| * Compresses large strings (`str.length > 1024`) into Uint8Arrays | ||
| * @param str - Input string to compress | ||
| * @returns Compressed Uint8Array | ||
| * @example | ||
| * await compressLargeToUint8Array('Hello, World!'); | ||
| * @since 2.1.0 | ||
| */ | ||
| export function compressLargeToUint8Array(str: string, options?: compressOptions): Promise<Uint8Array<ArrayBuffer>>; | ||
| /** | ||
| * JavaScript String Compressor - decompressFromBase64 function | ||
| * @param str - Compressed string in non-standard Base64 format | ||
| * @param str - Compressed string in non-standard Base64 format (`0-9` `a-z` `A-Z` `+` `/`) | ||
| * @returns Decompressed string/object/number | ||
@@ -205,3 +343,3 @@ * @example | ||
| * JavaScript String Compressor - decompressFromBase64 function | ||
| * @param str - Compressed string in non-standard Base64 format | ||
| * @param str - Compressed string in non-standard Base64 format (`0-9` `a-z` `A-Z` `+` `/`) | ||
| * @param stringify - Always return string? | ||
@@ -216,6 +354,6 @@ * @returns Decompressed string | ||
| * JavaScript String Compressor - decompressFromBase64 function | ||
| * @param str - Compressed string in non-standard Base64 format | ||
| * @param str - Compressed string in non-standard Base64 format (`0-9` `a-z` `A-Z` `+` `/`) | ||
| * @returns Decompressed string/object/number | ||
| * @example | ||
| * await decompressFromBase64(compressedString, true); | ||
| * await decompressFromBase64(compressedString); | ||
| * @since 2.1.0 | ||
@@ -226,2 +364,60 @@ */ | ||
| /** | ||
| * JavaScript String Compressor - decompressFromBase64URL function | ||
| * @param str - Compressed string in non-standard Base64URL format (`0-9` `a-z` `A-Z` `-` `_`) | ||
| * @returns Decompressed string/object/number | ||
| * @example | ||
| * await decompressFromBase64URL(compressedString); | ||
| * @since 2.1.0 | ||
| */ | ||
| export function decompressFromBase64URL(str: string): Promise<object|number|string>; | ||
| /** | ||
| * JavaScript String Compressor - decompressFromBase64URL function | ||
| * @param str - Compressed string in non-standard Base64URL format (`0-9` `a-z` `A-Z` `-` `_`) | ||
| * @param stringify - Always return string? | ||
| * @returns Decompressed string | ||
| * @example | ||
| * await decompressFromBase64URL(compressedString, true); | ||
| * @since 2.1.0 | ||
| */ | ||
| export function decompressFromBase64URL(str: string, stringify: true): Promise<string>; | ||
| /** | ||
| * JavaScript String Compressor - decompressFromBase64URL function | ||
| * @param str - Compressed string in non-standard Base64URL format (`0-9` `a-z` `A-Z` `-` `_`) | ||
| * @returns Decompressed string/object/number | ||
| * @example | ||
| * await decompressFromBase64URL(compressedString); | ||
| * @since 2.1.0 | ||
| */ | ||
| export function decompressFromBase64URL(str: string, options?: decompressOptions): Promise<object|number|string>; | ||
| /** | ||
| * JavaScript String Compressor - decompressFromUint8Array function | ||
| * @param uint8arr - Compressed Uint8Array | ||
| * @returns Decompressed string/object/number | ||
| * @example | ||
| * await decompressFromUint8Array(compressedString); | ||
| * @since 2.1.0 | ||
| */ | ||
| export function decompressFromUint8Array(uint8arr: Uint8Array<ArrayBuffer>): Promise<object|number|string>; | ||
| /** | ||
| * JavaScript String Compressor - decompressFromUint8Array function | ||
| * @param uint8arr - Compressed string Uint8Array | ||
| * @param stringify - Always return string? | ||
| * @returns Decompressed string | ||
| * @example | ||
| * await decompressFromUint8Array(compressedString, true); | ||
| * @since 2.1.0 | ||
| */ | ||
| export function decompressFromUint8Array(uint8arr: Uint8Array<ArrayBuffer>, stringify: true): Promise<string>; | ||
| /** | ||
| * JavaScript String Compressor - decompressFromUint8Array function | ||
| * @param uint8arr - Compressed string Uint8Array | ||
| * @returns Decompressed string/object/number | ||
| * @example | ||
| * await decompressFromUint8Array(compressedString); | ||
| * @since 2.1.0 | ||
| */ | ||
| export function decompressFromUint8Array(uint8arr: Uint8Array<ArrayBuffer>, options?: decompressOptions): Promise<object|number|string>; | ||
| /** | ||
| * JavaScript String Compressor - cache.clear function | ||
@@ -241,4 +437,37 @@ * | ||
| }; | ||
| const version: string, | ||
| const version: string; | ||
| const worker: { | ||
| url: string | URL; | ||
| }; | ||
| /** | ||
| * JavaScript String Compressor - JSSC Instance class | ||
| * @license MIT | ||
| * @copyright (c) 2025-2026 JustDeveloper <<https://justdeveloper.is-a.dev>> | ||
| * @since 2.2.0 | ||
| */ | ||
| declare class JSSC { | ||
| constructor(); | ||
| ID: string; | ||
| compress: typeof compress; | ||
| decompress: typeof decompress; | ||
| compressToBase64: typeof compressToBase64; | ||
| compressToBase64URL: typeof compressToBase64URL; | ||
| compressToUint8Array: typeof compressToUint8Array; | ||
| compressLarge: typeof compressLarge; | ||
| compressLargeToBase64: typeof compressLargeToBase64; | ||
| compressLargeToBase64URL: typeof compressLargeToBase64URL; | ||
| compressLargeToUint8Array: typeof compressLargeToUint8Array; | ||
| decompressFromBase64: typeof decompressFromBase64; | ||
| decompressFromBase64URL: typeof decompressFromBase64URL; | ||
| decompressFromUint8Array: typeof decompressFromUint8Array; | ||
| events: { | ||
| onCompressed: (input: string|object|number, output: string) => void; | ||
| onCompressProgress: (percentage: number) => void; | ||
| onCompressionMode: (modeID: number, input: string|object|number, output: string) => void; | ||
| onDecompressed: (input: string, output: string|object|number) => void; | ||
| } | ||
| }; | ||
| export { | ||
@@ -248,7 +477,15 @@ compress, | ||
| compressToBase64, | ||
| compressToBase64URL, | ||
| compressToUint8Array, | ||
| compressLarge, | ||
| compressLargeToBase64, | ||
| compressLargeToBase64URL, | ||
| compressLargeToUint8Array, | ||
| decompressFromBase64, | ||
| decompressFromBase64URL, | ||
| decompressFromUint8Array, | ||
| cache, | ||
| version, | ||
| worker, | ||
| JSSC | ||
| }; |
+21
-34
@@ -6,9 +6,9 @@ #!/usr/bin/env node | ||
| import os from 'os'; | ||
| import https from 'https'; | ||
| import { fileURLToPath } from 'url'; | ||
| const __dirname$2 = path.dirname(fileURLToPath(import.meta.url)); | ||
| const confirmPs1 = path.resolve(__dirname$2, "./ui/confirm.ps1"); | ||
| const welcomePs1 = path.resolve(__dirname$2, "./ui/welcome.ps1"); | ||
| path.resolve(__dirname$2, "./ui/compress.ps1"); | ||
| const uiDir = path.resolve(__dirname$2, "./ui"); | ||
| const confirmPs1 = path.resolve(uiDir, "./confirm.ps1"); | ||
| const welcomePs1 = path.resolve(uiDir, "./welcome.ps1"); | ||
| path.resolve(__dirname$2, "./windows/ui/compress.ps1"); | ||
@@ -72,2 +72,12 @@ function confirm(title, text, repo, site) { | ||
| function message(title, message, icon = 'Error') { | ||
| const psCommand = `powershell -Command "[System.Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms'); [System.Windows.Forms.MessageBox]::Show('${message}', '${title}', [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::${icon})"`; | ||
| try { | ||
| execSync(psCommand); | ||
| } catch (error) { | ||
| console.error(error); | ||
| } | ||
| } | ||
| if (process.platform !== "win32") { | ||
@@ -93,3 +103,2 @@ process.exit(0); | ||
| const ICON_URL = "https://jssc.js.org/favicon.ico"; | ||
| const APP_NAME = "JSSC"; | ||
@@ -105,3 +114,3 @@ const EXT = ".jssc"; | ||
| const localPkg = path.join(installDir, "pkg"); | ||
| const localBin = path.join(localPkg, "bin"); | ||
| const localBin = path.join(localPkg, "dist"); | ||
| const localCfg = path.join(installDir, "default.justc"); | ||
@@ -111,5 +120,6 @@ const localVbs = path.join(installDir, "jssc.vbs"); | ||
| const pkgRoot = path.resolve(__dirname$1, "../../"); | ||
| const cliPath = path.resolve(localBin, "./index.js"); | ||
| const cliPath = path.resolve(localBin, "./cli.js"); | ||
| const cfgPath = path.resolve(localBin, "./windows/default.justc"); | ||
| const vbsPath = path.resolve(localBin, "./windows/jssc.vbs"); | ||
| const icoPath = path.resolve(localBin, "./windows/icon.ico"); | ||
| const nodePath = process.execPath; | ||
@@ -124,24 +134,2 @@ | ||
| function downloadIcon() { | ||
| return new Promise((resolve, reject) => { | ||
| if (!fs.existsSync(installDir)) { | ||
| fs.mkdirSync(installDir, { recursive: true }); | ||
| } | ||
| const file = fs.createWriteStream(iconPath); | ||
| https.get(ICON_URL, res => { | ||
| if (res.statusCode !== 200) { | ||
| reject(new Error("Failed to download icon")); | ||
| return; | ||
| } | ||
| res.pipe(file); | ||
| file.on("finish", () => { | ||
| file.close(resolve); | ||
| }); | ||
| }).on("error", reject); | ||
| }); | ||
| } | ||
| function showProgress() { | ||
@@ -160,4 +148,2 @@ return spawn("powershell", [ | ||
| await downloadIcon(); | ||
| let e = [false, undefined]; | ||
@@ -173,5 +159,4 @@ try { | ||
| fs.copyFileSync(cfgPath, localCfg); | ||
| fs.rmSync(cfgPath); | ||
| fs.copyFileSync(vbsPath, localVbs); | ||
| fs.rmSync(vbsPath); | ||
| fs.copyFileSync(icoPath, iconPath); | ||
@@ -229,4 +214,6 @@ const vbs = `wscript.exe \\"${localVbs}\\" \\"${nodePath}\\" \\"${cliPath}\\"`; | ||
| repo, site)) setup().catch(err => { | ||
| console.error("Installation failed:", err.message); | ||
| const e = "Installation failed: " + err.message; | ||
| console.error(e, '\n' + err.trace); | ||
| message(name__, e); | ||
| process.exit(1); | ||
| }); |
| param ( | ||
| [string]$Name = "", | ||
| [string]$Text = "" | ||
| [string]$Text = "", | ||
| [int]$Progress = 0 | ||
| ) | ||
| [Windows.Forms.Application]::EnableVisualStyles() | ||
| Add-Type -AssemblyName System.Windows.Forms | ||
| Add-Type -AssemblyName System.Drawing | ||
| [Windows.Forms.Application]::EnableVisualStyles() | ||
| $form = New-Object Windows.Forms.Form | ||
| $form.Text = $Name | ||
| $form.Size = New-Object Drawing.Size(400, 90) | ||
| $form.Size = New-Object Drawing.Size(400, 120) | ||
| $form.StartPosition = "CenterScreen" | ||
@@ -22,8 +23,38 @@ $form.FormBorderStyle = "FixedDialog" | ||
| $label = New-Object Windows.Forms.Label | ||
| $label.Text = $Text | ||
| $label.Location = New-Object Drawing.Point(20, 20) | ||
| $label.Text = "$Text ($Progress%)" | ||
| $label.Location = New-Object Drawing.Point(20, 15) | ||
| $label.AutoSize = $true | ||
| $label.Font = New-Object System.Drawing.Font('Microsoft JhengHei',10) | ||
| $progressBar = New-Object Windows.Forms.ProgressBar | ||
| $progressBar.Location = New-Object Drawing.Point(20, 50) | ||
| $progressBar.Size = New-Object Drawing.Size(340, 20) | ||
| $progressBar.Minimum = 0 | ||
| $progressBar.Maximum = 100 | ||
| $progressBar.Value = $Progress | ||
| $form.Controls.Add($label) | ||
| $form.Controls.Add($progressBar) | ||
| $form.ShowDialog() | ||
| $timer = New-Object Windows.Forms.Timer | ||
| $timer.Interval = 100 | ||
| $timer.Add_Tick({ | ||
| while ([Console]::In.Peek() -ne -1) { | ||
| $line = [Console]::In.ReadLine() | ||
| if ($line -ne $null) { | ||
| $value = [int]$line | ||
| if ($value -ge 0 -and $value -le 100) { | ||
| $progressBar.Value = $value | ||
| $label.Text = "$Text ($value%)" | ||
| } | ||
| } | ||
| } | ||
| }) | ||
| $timer.Start() | ||
| $form.Add_Shown({ $form.Activate() }) | ||
| [void]$form.Show() | ||
| [Windows.Forms.Application]::Run($form) |
+6
-5
| { | ||
| "name": "strc", | ||
| "version": "2.1.0-test.1", | ||
| "version": "2.1.1-d", | ||
| "description": "JavaScript String Compressor - lossless string compression algorithm", | ||
@@ -113,5 +113,6 @@ "main": "dist/jssc.cjs", | ||
| "scripts": { | ||
| "test": "node test/run.cjs" | ||
| "test": "node test/test.cjs" | ||
| }, | ||
| "devDependencies": { | ||
| "@codecov/rollup-plugin": "^1.9.1", | ||
| "@rollup/plugin-commonjs": "^29.0.0", | ||
@@ -123,8 +124,8 @@ "@rollup/plugin-json": "^6.1.0", | ||
| "@strc/utf16-to-any-base": "^2.0.2", | ||
| "crc-32": "^1.2.2", | ||
| "lz-string": "^1.5.0", | ||
| "semver": "^7.7.4", | ||
| "uint8arrays": "^5.1.0", | ||
| "utf8": "^3.0.0", | ||
| "@strc/utf16-to-any-base": "^1.0.0", | ||
| "crc-32": "^1.2.2" | ||
| "utf8": "^3.0.0" | ||
| }, | ||
@@ -131,0 +132,0 @@ "module": "dist/jssc.mjs", |
+39
-95
@@ -1,89 +0,43 @@ | ||
| # JSSC — JavaScript String Compressor | ||
| **JSSC (JavaScript String Compressor)** is an open-source, **lossless string compression algorithm** designed specifically for JavaScript. | ||
|  | ||
| It operates directly on JavaScript strings (UTF-16) and produces compressed data that is also a valid JavaScript string. | ||
| # JSSC — JavaScript String Compressor <br> [<img src="https://nodei.co/npm/strc.svg?style=shields&data=d&color=blue" alt="NPM" align="center" />](https://www.npmjs.com/package/strc) [<img src="https://badge.socket.dev/npm/package/strc/latest" alt="Socket score" align="center" />](https://socket.dev/npm/package/strc/) [<img src="https://github.com/justdevw/JSSC/actions/workflows/ci.yml/badge.svg" alt="CI" align="center" />](https://github.com/justdevw/JSSC/actions/workflows/ci.yml) [<img src="https://img.shields.io/github/license/justdevw/jssc?label=License" align="center" alt="License" />](https://github.com/justdevw/JSSC/blob/main/LICENSE) | ||
| ## Key Features | ||
| - ✨ **Lossless compression** | ||
| - 🗜️ **High compression ratios** | ||
| - up to **8:1** for numeric data | ||
| - strong results for repetitive and structured text | ||
| - 🌍 **Multilingual support** | ||
| - English, Russian, Japanese, Chinese, Hindi, Bengali, and more | ||
| - 📦 **JSON support** | ||
| - JSON is converted to [JUSTC](https://just.js.org/justc) before compression | ||
| - ⚙️ **String → String** | ||
| - no binary buffers | ||
| - no external metadata | ||
| - all required information is embedded into the compressed string itself | ||
| - 🧠 **Self-validating compression** | ||
| - every compression mode is verified by decompression before being accepted | ||
| - 🔁 **Recursive compression** | ||
| - 📜 **TypeScript definitions** included | ||
| JSSC is an open-source, **lossless string compression algorithm** designed specifically for JavaScript strings (UTF-16). It produces compressed data that remains a valid JS string, making it ideal for environments where binary data is difficult to handle. | ||
| ## Important Version Compatibility Notice | ||
| ⚠️ **Compressed strings produced by JSSC v1.x.x are NOT compatible with v2.x.x** | ||
| > **Note:** The npm package is named [`strc`](https://www.npmjs.com/package/strc). <br> | ||
| > The `jssc` ("jSSC") npm package is unrelated to this project. <br> | ||
| > Both names (uppercase "JSSC" and lowercase "strc") refer to the same project. | ||
| Reasons: | ||
| - The first 16 bits (header layout) were slightly redesigned | ||
| - New compression modes were added | ||
| - Character encoding tables were extended | ||
| JSSC is a complex algorithm featuring multiple internal compression modes tailored for different data structures. During compression, each mode evaluates the input; if its specific conditions are met, it produces a **candidate** string. JSSC then selects the best candidate — the one that achieves the highest compression ratio while passing a mandatory lossless decompression check. This approach results in a slower compression phase but ensures **high compression ratio** and **fast decompression**, as no brute-forcing or validation is required during recovery. | ||
| ## Character Encoding | ||
| JSSC operates on **JavaScript UTF-16 code units**, not on UTF-8 bytes. | ||
| > ⚠️ **Compatibility Notice:** Compressed strings from v1.x.x are **not compatible** with v2.x.x due to header and encoding changes. JSSC follows Semantic Versioning: successful decompression is guaranteed only if the decompressor version is equal to or newer than the compressor version (within the same major version). | ||
| This means: | ||
| - Any character representable in a JavaScript string is supported | ||
| - Compression works at the UTF-16 level | ||
| - One JavaScript character = **16 bits** | ||
| - Binary data must be converted to strings before compression | ||
| ## Key Features | ||
| - ~**2.5:1 average compression ratio**. | ||
| - **String-to-String**: No binary buffers or external metadata. | ||
| - **Self-validating**: Compressed string is guaranteed to be successfully decompressed and with no data loss. | ||
| > If the string was corrupted or compressed by a later version or if it was compressed with a different major version following the [Semantic Versioning](https://semver.org/) standard, then there is no guarantee that the compressed string will be successfully decompressible without any data loss. | ||
| - **TypeScript support** and a fully-typed API. | ||
| ## Project Name vs npm Package Name | ||
| The project is called **JSSC** (JavaScript String Compressor). | ||
| ## Documentation | ||
| Full documentation, API reference, and live examples are available at **[jssc.js.org](https://jssc.js.org/)**. | ||
| The npm package is published under the name **`strc`**, because the name `jssc` is already occupied on npm by an unrelated Java-based package. | ||
| Both names refer to the same project. | ||
| ## Installation | ||
| Install via npm | ||
| ## Quick start | ||
| ``` | ||
| npm i strc | ||
| ``` | ||
| > The npm package name is `strc`, but the library itself is **JSSC**. | ||
| Or you can use it on your website by inserting the following HTML `script` tags. | ||
| ```html | ||
| <script src="https://unpkg.com/justc"></script> | ||
| <script src="https://unpkg.com/strc"></script> | ||
| ``` | ||
| ## Usage | ||
| #### JavaScript | ||
| ```js | ||
| const { compress, decompress } = require('strc'); | ||
| const example = await compress("Hello, world!"); | ||
| await decompress(example); | ||
| ``` | ||
| #### TypeScript | ||
| ```ts | ||
| import { compress, decompress } from 'strc'; | ||
| const example = await compress("Hello, world!"); | ||
| await decompress(example); | ||
| const data = "Hello, world!"; | ||
| const compressed = await compress(data); | ||
| const original = await decompress(compressed); | ||
| ``` | ||
| #### Deno (server-side) | ||
| ```ts | ||
| import JSSC from 'https://jssc.js.org/jssc.min.js'; | ||
| const example = await JSSC.compress("Hello, world!"); | ||
| await JSSC.decompress(example); | ||
| CLI: | ||
| ``` | ||
| npx jssc --help | ||
| ``` | ||
| #### Browsers / Frontend (UMD) | ||
| When using the UMD build via CDN, the library is exposed globally as `JSSC`. | ||
| Website/Browsers: | ||
| ```html | ||
@@ -94,38 +48,28 @@ <script src="https://unpkg.com/justc"></script> | ||
| ```js | ||
| const compressed = await JSSC.compress("Hello, world!"); | ||
| const decompressed = await JSSC.decompress(compressed); | ||
| const data = "Hello, world!"; | ||
| const compressed = await JSSC.compress(data); | ||
| const original = await JSSC.decompress(compressed); | ||
| ``` | ||
| ## JS API | ||
| #### `compress(input: string | object | number): Promise<string>` | ||
| Compresses the input and returns a compressed JavaScript string. | ||
| #### `decompress(input: string, stringify?: boolean): Promise<string | object | number>` | ||
| Decompresses a previously compressed string/object/integer. | ||
| ## CLI Usage | ||
| ``` | ||
| jssc --help | ||
| ``` | ||
| **Compress a file/directory to JSSC Archive:** | ||
| ``` | ||
| jssc <input> | ||
| ``` | ||
| **Decompress a JSSC Archive:** | ||
| ``` | ||
| jssc <input.jssc> -d | ||
| ``` | ||
| ## Dependencies | ||
| JSSC depends on: | ||
| - <img align="top" src="https://just.js.org/justc/logo-50.svg" alt="JUSTC Logo" width="26" height="26"> [JUSTC](https://just.js.org/justc) by [JustStudio.](https://juststudio.is-a.dev/) | ||
| - [lz-string](https://github.com/pieroxy/lz-string/) by [pieroxy](https://github.com/pieroxy) | ||
| - [unicode-emoji-json](https://www.npmjs.com/package/unicode-emoji-json) by [Mu-An Chiou](https://github.com/muan) | ||
| - [utf8.js](https://github.com/mathiasbynens/utf8.js) by [Mathias Bynens](https://mathiasbynens.be/) | ||
| <br> | ||
| JSSC CLI and Format Handling depends on: | ||
| JSSC CLI and format handling (`.jssc`) depends on: | ||
| - [crc-32](https://www.npmjs.com/package/crc-32) by [SheetJS](https://sheetjs.com/) | ||
| - [semver](https://semver.npmjs.com/) by [npm](https://www.npmjs.com/) | ||
| - [uint8arrays](https://www.npmjs.com/package/uint8arrays) by [Alex Potsides](https://github.com/achingbrain) | ||
| - [semver](https://semver.npmjs.com/) by [npm](https://www.npmjs.com/) | ||
| <br> | ||
| > **Note:** All dependencies (except **JUSTC**) are bundled into the final build. | ||
| ## License | ||
| [MIT © 2025-2026 JustDeveloper](https://github.com/justdevw/JSSC/blob/main/LICENSE) | ||
| --- | ||
| [](https://www.npmjs.com/package/strc) |
-116
| const JSSC = require('../dist/jssc.cjs'); | ||
| function stringChunks(str, num) { | ||
| const output = []; | ||
| for (let i = 0; i < str.length; i += num) { | ||
| output.push(str.slice(i, i + num)) | ||
| } | ||
| return output | ||
| } | ||
| const encodings = [ | ||
| '00: JSSCBASE', | ||
| '01: JSSCRU', | ||
| '02: JSSCENRU', | ||
| '03: JSSCENKK', | ||
| '04: JSSCHI', | ||
| '05: JSSCENHI', | ||
| '06: JSSCBN', | ||
| '07: JSSCENBN', | ||
| '08: JSSCHIBN', | ||
| '09: JSSCJA', | ||
| '10: JSSCTelu', | ||
| '11: JSSCMR', | ||
| '12: JSSCB', | ||
| '13: JSSCE', | ||
| '14: JSSCAR', | ||
| ]; | ||
| const modes = [ | ||
| '00: No Compression', | ||
| '01: Two-Digit CharCode Concatenation', | ||
| '02: Two-Byte CharCode Concatenation', | ||
| '03: Decimal Integer Packing', | ||
| '04: Alphabet Encoding', | ||
| '05: Character Encoding', | ||
| '06: Inline Integer Encoding', | ||
| '07: Frequency Map', | ||
| '08: URL', | ||
| '09: Segmentation', | ||
| '10: String Repetition', | ||
| '12: Emoji Packing', | ||
| '13: Base-64 Integer Encoding', | ||
| '14: Base-64 Packing', | ||
| '17: Segmentation', | ||
| 'RESERVED', | ||
| 'RESERVED', | ||
| 'RESERVED', | ||
| 'RESERVED', | ||
| 'RESERVED', | ||
| 'RESERVED', | ||
| 'RESERVED', | ||
| 'RESERVED', | ||
| 'RESERVED', | ||
| 'RESERVED', | ||
| 'RESERVED', | ||
| 'RESERVED', | ||
| 'RESERVED', | ||
| 'RESERVED', | ||
| '16: lzstring', | ||
| '15: Offset Encoding', | ||
| '11: Recursive compression', | ||
| ]; | ||
| async function test(text, name) { | ||
| console.info('\n\n\n\n\nRunning compress tests (', name, ') ...'); | ||
| const a = await JSSC.compress(text); | ||
| const b = await JSSC.decompress(a); | ||
| const c = a.charCodeAt(0).toString(2).padStart(16, '0'); | ||
| const toString = typeof text != 'object' ? String(text) : JSON.stringify(text); | ||
| const data = a.slice(0,1); | ||
| const bits = stringChunks(c, 4).join(' '); | ||
| const blocks = []; | ||
| const code = []; | ||
| for (const [x,y] of [ | ||
| [0,4], [4,5], | ||
| [5,8], [8,9], | ||
| [9,10], [10,11], [11] | ||
| ]) blocks.push(c.slice(x,y)); | ||
| for (const [x,y] of [ | ||
| [11], [0,4], [5,8] | ||
| ]) code.push(parseInt(c.slice(x,y), 2)); | ||
| const success = [ | ||
| text == b, | ||
| a.length <= toString.length, | ||
| ]; | ||
| const result = success[0] && success[1]; | ||
| console.log( | ||
| '\n\n\nOriginal:', text, '\n\nCompressed:', a, '\n\nDecompressed:', b, | ||
| '\n\n\nSuccess?', result, '(Decompressed successfully?', success[0], '; Compressed size ≤ Original size?', success[1], ')\nOriginal size:', toString.length * 16, 'bits\nCompressed size:', a.length * 16, 'bits\nSaved:', toString.length * 16 - a.length * 16, 'bits\nRatio:', (toString.length * 16) / (a.length * 16), | ||
| ': 1\n\n\n16-bit Data/Header character:', data, '\nCharCode:', data.charCodeAt(0), '\nBits:', bits, '\nBlocks:', ...blocks, '\nCode 1:', code[0], '\nCode 2:', code[1], c.slice(10,11) == '1' ? '\nBeginID:' : '\nCode 3:', code[2], '\nSequences?', c.slice(4,5) == '1', (code[1] > 0 && code[0] == 0) || code[0] == 6 ? '\nReturn as number?' : '\nInput RLE?', c.slice(8,9) == '1', '\nOutput RLE?', c.slice(9,10) == '1', '\nCode 3 is BeginID?', c.slice(10,11) == '1', | ||
| '\n\nMode:', modes[code[0]], code[0] == 5 ? '\nCharacter Encoding:' : code[0] == 31 ? '\nCompressed:' : '', code[0] == 5 ? encodings[code[1]] : code[0] == 31 ? code[1] + 1 : '', code[0] == 31 ? 'times' : '', '\n\n\n\n\n' | ||
| ); | ||
| return result; | ||
| } | ||
| async function runTest(text = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.', name = 'Lorem ipsum') { | ||
| const result = await test(text, name); | ||
| if (!result) throw new Error('Failed to decompress. decompress(text) != text'); | ||
| } | ||
| const tests = async function () { | ||
| await runTest(); | ||
| await runTest('foo'.repeat(1000), 'foo x1000'); | ||
| await runTest('ыалалыылаар', 'ыалалыылаар'); | ||
| await runTest(String(Math.round(Math.random() * 256000000)), 'random numbers'); | ||
| await runTest('asdasdsasdsadsdadsadssssssssssssssssssssыꙮ'.repeat(15), 'absolutely random stuff'); | ||
| await runTest('aaaaaaaaaaaaaaa1ыыыыыыыыыыыыыꙮ'.repeat(30), 'should use recursive compression mode'); | ||
| } | ||
| tests().then(()=>{}); |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
Unpublished package
Supply chain riskPackage version was not found on the registry. It may exist on a different registry and need to be configured to pull from that registry.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 3 instances in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
Deprecated
MaintenanceThe maintainer of the package marked it as deprecated. This could indicate that a single version should not be used, or that the package is no longer maintained and any new vulnerabilities will not be fixed.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 2 instances in 1 package
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
Unpopular package
QualityThis package is not very popular.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 3 instances in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
0
-100%0
-100%3
-70%1025631
-6.61%12
9.09%20208
-31.96%75
-42.75%123
241.67%