mirror of
https://github.com/qntm/base65536
synced 2026-03-26 17:24:46 +01:00
Compare commits
6 Commits
1ef6e737f4
...
4add117c13
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4add117c13 | ||
|
|
9ccc24279a | ||
|
|
3649e78b61 | ||
|
|
0fa0837532 | ||
|
|
8e02e67065 | ||
|
|
cf966f1df0 |
@ -1,7 +1,7 @@
|
||||
[*]
|
||||
insert_final_newline = true
|
||||
|
||||
[{*.js,*.json,*.ts,*.md}]
|
||||
[{*.js,*.json,*.ts,*.md,*.html}]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@ -46,4 +46,4 @@ Network Trash Folder
|
||||
Temporary Items
|
||||
.apdisk
|
||||
node_modules
|
||||
dist
|
||||
coverage
|
||||
|
||||
21
CHANGELOG.md
Normal file
21
CHANGELOG.md
Normal file
@ -0,0 +1,21 @@
|
||||
# CHANGELOG
|
||||
|
||||
## 4.x.x
|
||||
|
||||
`base65536` now ships as JavaScript ("ES6") modules, not CommonJS modules. The package has `"type": "module"`. Additionally a separate IIFE for browser use is no longer distributed.
|
||||
|
||||
## 3.x.x
|
||||
|
||||
`encode` and `decode` now use `Uint8Arrays`, not `ArrayBuffer`s. The options `ignoreGarbage` and `wrap` have been scrapped.
|
||||
|
||||
## 2.x.x
|
||||
|
||||
`encode` and `decode` now operate on environment-agnostic `ArrayBuffer`s instead of Node.js-specific `Buffer`s.
|
||||
|
||||
## 1.x.x
|
||||
|
||||
No breaking changes; in this version, the code point repertoire was deemed final.
|
||||
|
||||
## 0.0.x
|
||||
|
||||
Prototype release.
|
||||
11
README.md
11
README.md
@ -136,17 +136,6 @@ console.log(uint8Array2);
|
||||
// [104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100]
|
||||
```
|
||||
|
||||
### In the browser
|
||||
|
||||
Load this file in the browser to gain access to a `base65536` global.
|
||||
|
||||
```html
|
||||
<script src='https://unpkg.com/base65536@3/dist/iife/base65536.js' crossorigin></script>
|
||||
<script>
|
||||
console.log(base65536.decode('驨ꍬ啯𒁷ꍲᕤ'))
|
||||
</script>
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
`base65536` accepts and returns `Uint8Array`s. Note that every Node.js `Buffer` is a `Uint8Array`. A `Uint8Array` can be converted to a Node.js `Buffer` like so:
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
{
|
||||
"fixturesFolder": false,
|
||||
"integrationFolder": "test-built",
|
||||
"pluginsFile": false,
|
||||
"screenshotOnRunFailure": false,
|
||||
"supportFile": false,
|
||||
|
||||
8
cypress/integration/index.spec.js
Normal file
8
cypress/integration/index.spec.js
Normal file
@ -0,0 +1,8 @@
|
||||
/* global describe, it, cy */
|
||||
|
||||
describe('base65536 in the browser', () => {
|
||||
it('works', () => {
|
||||
cy.visit('http://localhost:3000/server/index.html')
|
||||
cy.contains('what the heck is up')
|
||||
})
|
||||
})
|
||||
8645
package-lock.json
generated
Normal file
8645
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
28
package.json
28
package.json
@ -1,28 +1,24 @@
|
||||
{
|
||||
"name": "base65536",
|
||||
"version": "3.0.3",
|
||||
"version": "4.0.1",
|
||||
"description": "Unicode's answer to Base64",
|
||||
"homepage": "https://github.com/qntm/base65536",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/qntm/base65536.git"
|
||||
},
|
||||
"module": "dist/es6/base65536.js",
|
||||
"main": "dist/cjs/base65536.js",
|
||||
"type": "module",
|
||||
"main": "src",
|
||||
"types": "typings/index.d.ts",
|
||||
"scripts": {
|
||||
"build": "rollup -c rollup.config.js",
|
||||
"jest": "jest",
|
||||
"cypress": "start-server-and-test \"node server/server.js\" http://localhost:3000/server/index.html \"cypress run\"",
|
||||
"postpublish": "npm version patch && git push",
|
||||
"jest": "cross-env NODE_OPTIONS=--experimental-vm-modules npx jest --coverage --transform {} --testPathIgnorePatterns cypress",
|
||||
"standard": "standard",
|
||||
"test": "standard && jest",
|
||||
"test-built": "npm run test-built-cjs && npm run test-built-es6 && npm run test-built-iife",
|
||||
"test-built-cjs": "node test-built/cjs.js",
|
||||
"test-built-es6": "babel-node test-built/es6.js",
|
||||
"test-built-iife": "start-server-and-test \"node test-built/server.js\" http://localhost:3000/test-built/index.html \"cypress run --spec test-built/iife.js\""
|
||||
"test": "npm run standard && npm run jest && npm run cypress"
|
||||
},
|
||||
"keywords": [
|
||||
"base64",
|
||||
"base65536",
|
||||
"encoding",
|
||||
"unicode",
|
||||
"text",
|
||||
@ -32,15 +28,16 @@
|
||||
"author": "qntm",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@babel/eslint-parser": "^7.15.0",
|
||||
"@babel/node": "^7.10.5",
|
||||
"@babel/preset-env": "^7.8.4",
|
||||
"base65536-test": "^1.1.2",
|
||||
"cross-env": "^7.0.3",
|
||||
"cypress": "^8.3.1",
|
||||
"express": "^4.17.1",
|
||||
"glob": "^7.1.6",
|
||||
"jest": "^27.0.3",
|
||||
"rollup": "^2.26.3",
|
||||
"safe-code-point": "^2.0.0",
|
||||
"safe-code-point": "^3.0.0",
|
||||
"standard": "^16.0.1",
|
||||
"start-server-and-test": "^1.11.3"
|
||||
},
|
||||
@ -50,10 +47,11 @@
|
||||
]
|
||||
},
|
||||
"standard": {
|
||||
"ignore": "dist"
|
||||
"parser": "@babel/eslint-parser"
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
"src",
|
||||
"!*.spec.js",
|
||||
"typings"
|
||||
]
|
||||
}
|
||||
|
||||
@ -1,23 +0,0 @@
|
||||
module.exports = [{
|
||||
// nearly indistinguishable from a copy and paste of the source
|
||||
input: 'src/index.js',
|
||||
output: {
|
||||
file: 'dist/es6/base65536.js',
|
||||
format: 'esm'
|
||||
}
|
||||
}, {
|
||||
// same as above but Node.js-friendly
|
||||
input: 'src/index.js',
|
||||
output: {
|
||||
file: 'dist/cjs/base65536.js',
|
||||
format: 'cjs'
|
||||
}
|
||||
}, {
|
||||
// this can be imported into the browser as a script
|
||||
input: 'src/index.js',
|
||||
output: {
|
||||
file: 'dist/iife/base65536.js',
|
||||
format: 'iife',
|
||||
name: 'base65536'
|
||||
}
|
||||
}]
|
||||
@ -21,44 +21,40 @@
|
||||
import SafeCodePoint from 'safe-code-point'
|
||||
|
||||
// Well these ergonomics are dreadful huh
|
||||
export default () => SafeCodePoint('8.0.0').then(safeCodePoint => {
|
||||
const safeRange = (min, max) => {
|
||||
for (let codePoint = min; codePoint < max; codePoint++) {
|
||||
// Code points were chosen entirely from the "Letter, other" general
|
||||
// category, for reasons which I no longer recall. Unicode 8.0 was current
|
||||
// at the time.
|
||||
if (
|
||||
safeCodePoint.generalCategory(codePoint) !== 'Lo' ||
|
||||
!safeCodePoint(codePoint)
|
||||
) {
|
||||
return false
|
||||
}
|
||||
const safeCodePoint = await SafeCodePoint('8.0.0')
|
||||
|
||||
const safeRange = (min, max) => {
|
||||
for (let codePoint = min; codePoint < max; codePoint++) {
|
||||
// Code points were chosen entirely from the "Letter, other" general
|
||||
// category, for reasons which I no longer recall. Unicode 8.0 was current
|
||||
// at the time.
|
||||
if (
|
||||
safeCodePoint.generalCategory(codePoint) !== 'Lo' ||
|
||||
!safeCodePoint(codePoint)
|
||||
) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
const getAllSafeRanges = rangeSize => {
|
||||
const allSafeRanges = []
|
||||
for (let codePoint = 0; codePoint < (1 << 16) + (1 << 20); codePoint += rangeSize) {
|
||||
if (safeRange(codePoint, codePoint + rangeSize)) {
|
||||
allSafeRanges.push(codePoint)
|
||||
}
|
||||
const getAllSafeRanges = rangeSize => {
|
||||
const allSafeRanges = []
|
||||
for (let codePoint = 0; codePoint < (1 << 16) + (1 << 20); codePoint += rangeSize) {
|
||||
if (safeRange(codePoint, codePoint + rangeSize)) {
|
||||
allSafeRanges.push(codePoint)
|
||||
}
|
||||
return allSafeRanges
|
||||
}
|
||||
return allSafeRanges
|
||||
}
|
||||
|
||||
const allSafeRanges = getAllSafeRanges(1 << 8)
|
||||
const allSafeRanges = getAllSafeRanges(1 << 8)
|
||||
|
||||
const paddingBlockStart = String.fromCodePoint(allSafeRanges.shift())
|
||||
const paddingBlockStart = String.fromCodePoint(allSafeRanges.shift())
|
||||
|
||||
const blockStarts = allSafeRanges.slice(0, 1 << 8).map(x => String.fromCodePoint(x)).join('')
|
||||
const blockStarts = allSafeRanges.slice(0, 1 << 8).map(x => String.fromCodePoint(x)).join('')
|
||||
|
||||
return {
|
||||
safeCodePoint,
|
||||
paddingBlockStart,
|
||||
blockStarts
|
||||
}
|
||||
})
|
||||
export { safeCodePoint, paddingBlockStart, blockStarts }
|
||||
|
||||
// There are now implementations of
|
||||
// Base65536 in numerous programming languages beyond the original JavaScript,
|
||||
|
||||
@ -1,22 +1,14 @@
|
||||
/* eslint-env jest */
|
||||
|
||||
import gen from './gen'
|
||||
import { paddingBlockStart, blockStarts, safeCodePoint } from './gen'
|
||||
|
||||
describe('gen', () => {
|
||||
let generated
|
||||
|
||||
beforeAll(() =>
|
||||
gen().then(g => {
|
||||
generated = g
|
||||
})
|
||||
)
|
||||
|
||||
it('generates the correct padding block', () => {
|
||||
expect(generated.paddingBlockStart).toBe('ᔀ')
|
||||
expect(paddingBlockStart).toBe('ᔀ')
|
||||
})
|
||||
|
||||
it('generates the correct blocks', () => {
|
||||
expect(generated.blockStarts).toBe(
|
||||
expect(blockStarts).toBe(
|
||||
'㐀㔀㘀㜀㠀㤀㨀㬀㰀㴀㸀㼀䀀䄀䈀䌀' +
|
||||
'䐀䔀䘀䜀䠀䤀䨀䬀䰀一伀倀儀刀匀吀' +
|
||||
'唀嘀圀堀夀娀嬀尀崀帀开怀愀戀挀搀' +
|
||||
@ -41,7 +33,7 @@ describe('gen', () => {
|
||||
// 243 of the blocks are 'W' (wide), the other 13 + 1 are 'N' (neutral,
|
||||
// which in effect is narrow). This is significant when considering
|
||||
// rendering and wrapping.
|
||||
const allBlockStarts = [...generated.blockStarts].map(x => x.codePointAt(0))
|
||||
const allBlockStarts = [...blockStarts].map(x => x.codePointAt(0))
|
||||
const neutralBlockStarts = [...'ᔀꔀ𐘀𒀀𒄀𒈀𓀀𓄀𓈀𓌀𔐀𔔀𖠀𖤀'].map(x => x.codePointAt(0))
|
||||
allBlockStarts.forEach(blockStart => {
|
||||
for (let i = 0; i < 1 << 8; i++) {
|
||||
@ -51,7 +43,7 @@ describe('gen', () => {
|
||||
neutralBlockStart <= codePoint &&
|
||||
codePoint < neutralBlockStart + (1 << 8)
|
||||
)
|
||||
expect(generated.safeCodePoint.eastAsianWidth(codePoint)).toBe(isInNeutralBlock ? 'N' : 'W')
|
||||
expect(safeCodePoint.eastAsianWidth(codePoint)).toBe(isInNeutralBlock ? 'N' : 'W')
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
16
server/index.html
Normal file
16
server/index.html
Normal file
@ -0,0 +1,16 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Base65536</title>
|
||||
|
||||
<script type="module">
|
||||
import { encode, decode } from '../src/index.js'
|
||||
const encoded = encode(new TextEncoder('utf-8').encode('what the heck is up'))
|
||||
const decoded = new TextDecoder('utf-8').decode(decode(encoded))
|
||||
document.querySelector('.root').appendChild(document.createTextNode(decoded))
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="root"></div>
|
||||
</body>
|
||||
</html>
|
||||
@ -1,4 +1,5 @@
|
||||
const express = require('express')
|
||||
import express from 'express'
|
||||
|
||||
const app = express()
|
||||
app.use(express.static('.'))
|
||||
app.listen(3000, () => {
|
||||
@ -15,8 +15,8 @@ const BITS_PER_BYTE = 8
|
||||
|
||||
// Compressed representation of inclusive-exclusive ranges of characters used in this encoding.
|
||||
const pairStrings = [
|
||||
'㐀䴀一鼀ꄀꐀꔀꘀ𐘀𐜀𒀀𒌀𓀀𓐀𔐀𔘀𖠀𖨀𠀀𨘀',
|
||||
'ᔀᘀ'
|
||||
'㐀䳿一黿ꄀꏿꔀꗿ𐘀<EFBFBD>𒀀<EFBFBD>𓀀<EFBFBD>𔐀<EFBFBD>𖠀<EFBFBD>𠀀<EFBFBD>',
|
||||
'ᔀᗿ'
|
||||
]
|
||||
|
||||
// Decompression
|
||||
@ -28,7 +28,7 @@ pairStrings.forEach((pairString, r) => {
|
||||
let z2 = 0
|
||||
pairString.match(/../gu).forEach(pair => {
|
||||
const [first, last] = [...pair].map(x => x.codePointAt(0))
|
||||
for (let codePoint = first; codePoint < last; codePoint++) {
|
||||
for (let codePoint = first; codePoint <= last; codePoint++) {
|
||||
const chr = String.fromCodePoint(codePoint)
|
||||
|
||||
// SPECIAL CASE: flip the bytes around, because Base65536 was constructed to take the bytes
|
||||
|
||||
@ -1,8 +0,0 @@
|
||||
const { encode, decode } = require('..')
|
||||
|
||||
const before = [1, 2, 3]
|
||||
const after = Array.from(decode(encode(Uint8Array.from(before))))
|
||||
|
||||
if (JSON.stringify(after) !== JSON.stringify(before)) {
|
||||
throw Error()
|
||||
}
|
||||
@ -1,10 +0,0 @@
|
||||
// I want to write '..' here, but I can't figure out a way to get Babel to
|
||||
// follow `package.json`'s "module" property instead of its "main" property
|
||||
import { encode, decode } from '../dist/es6/base65536'
|
||||
|
||||
const before = [1, 2, 3]
|
||||
const after = Array.from(decode(encode(Uint8Array.from(before))))
|
||||
|
||||
if (JSON.stringify(after) !== JSON.stringify(before)) {
|
||||
throw Error()
|
||||
}
|
||||
@ -1,8 +0,0 @@
|
||||
/* global describe, it, cy */
|
||||
|
||||
describe('base65536 IIFE', () => {
|
||||
it('works', () => {
|
||||
cy.visit('http://localhost:3000/test-built/index.html')
|
||||
cy.contains('what the heck is up')
|
||||
})
|
||||
})
|
||||
@ -1,17 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title></title>
|
||||
<script crossorigin src="../dist/iife/base65536.js"></script>
|
||||
<script>
|
||||
window.addEventListener('load', () => {
|
||||
const encoded = base65536.encode(new TextEncoder('utf-8').encode('what the heck is up'))
|
||||
const decoded = new TextDecoder('utf-8').decode(base65536.decode(encoded))
|
||||
document.querySelector('.root').appendChild(document.createTextNode(decoded))
|
||||
})
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="root"></div>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
x
Reference in New Issue
Block a user