Skip to content

Commit

Permalink
Merge pull request #12 from dojyorin/dev
Browse files Browse the repository at this point in the history
update.
  • Loading branch information
dojyorin authored Nov 20, 2022
2 parents ed569cb + d26349b commit cb3f38d
Show file tree
Hide file tree
Showing 13 changed files with 132 additions and 66 deletions.
53 changes: 25 additions & 28 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,25 @@ A handy utility collection.
const file = await Deno.readFile("/path/to/binary.bin");

const encoded = base64Encode(file); // BASE64 encoded string.
const decoded = base64Decode(encoded); // Restored byte array.
const decoded = base64Decode(encoded); // Restored byte.
```

**Date UnixTime**

```ts
const date = new Date();

const encoded = await dateEncode(date); // UTC unix time.
const decoded = await dateDecode(encoded); // Restored Date object.
```

**DEFLATE Compress**

```ts
const file = await Deno.readFile("/path/to/binary.bin");

const encoded = await deflateEncode(file); // DEFLATE compressed byte array.
const decoded = await deflateDecode(encoded); // Restored byte array.
const encoded = await deflateEncode(file); // DEFLATE compressed byte.
const decoded = await deflateDecode(encoded); // Restored byte.
```

**Extended Fetch API**
Expand All @@ -34,11 +43,20 @@ const bytes = await fetchExtend("https://path/to/get", "byte"); // Response as U

```ts
const files = [
new File([await Deno.readFile("/path/to/binary.bin")], "binary.bin")
["binary.bin", Deno.readFileSync("/path/to/binary.bin")]
];

const encoded = await minipackEncode(files); // Minipack archived byte array.
const decoded = await minipackDecode(encoded); // Restored file object array.
const encoded = await minipackEncode(files); // Minipack archived byte.
const decoded = await minipackDecode(encoded); // Restored array of name and byte.
```

**Text Convert**

```ts
const text = "Lorem ipsum dolor sit amet.";

const encoded = await textEncode(text); // UTF-8 byte.
const decoded = await textDecode(encoded); // Restored string.
```

# Details
Expand Down Expand Up @@ -68,25 +86,4 @@ The actual binary structure looks like this:
This is for one file and repeats for the number of files.

# API
## `Uint8Array base64Encode(data)`
- `data` ... The byte array.

## `Uint8Array base64Decode(data)`
- `data` ... The BASE64 code.

## `Promise<Uint8Array> deflateEncode(data)`
- `data` ... The byte array.

## `Promise<Uint8Array> deflateDecode(data)`
- `data` ... The deflate compressed byte array.

## `<FetchResponseType<T>> fetchExtend<T>(path, type, option)`
- `path` ... Target URL. Since the query string is ignored, please specify it in the `option.query` property instead of writing it directly in the URL.
- `type` ... The type you want to receive in the response.
- `option` ... Fetch option. `window` is removed from `RequestInit` and `query` is added to write the query string.

## `Promise<Uint8Array> minipackEncode(files)`
- `files` ... Array of file object.

## `Promise<File[]> minipackDecode(archive)`
- `data` ... The minipack archived byte array.
See [Deno Document](https://deno.land/x/simple_utility/mod.ts) for details.
1 change: 0 additions & 1 deletion deps.ts
Original file line number Diff line number Diff line change
@@ -1 +0,0 @@
export {type JsonValue} from "https://deno.land/[email protected]/encoding/json/stream.ts";
4 changes: 3 additions & 1 deletion mod.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import "./test/base64.test.ts";
import "./test/date.test.ts";
import "./test/deflate.test.ts";
import "./test/fetch.test.ts";
import "./test/minipack.test.ts";
import "./test/minipack.test.ts";
import "./test/text.test.ts";
4 changes: 3 additions & 1 deletion mod.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
export * from "./src/base64.ts";
export * from "./src/date.ts";
export * from "./src/deflate.ts";
export * from "./src/fetch.ts";
export * from "./src/minipack.ts";
export * from "./src/minipack.ts";
export * from "./src/text.ts";
10 changes: 5 additions & 5 deletions src/base64.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
/**
* Convert from BASE64 code to byte array.
* @param data The byte array.
**/
* Convert from BASE64 code to byte.
* @param data The byte.
*/
export function base64Encode(data:Uint8Array){
return btoa([...data].map(n => String.fromCharCode(n)).join(""));
}

/**
* Convert from byte array to BASE64 code.
* Convert from byte to BASE64 code.
* @param data The base64 code.
**/
*/
export function base64Decode(data:string){
return new Uint8Array([...atob(data)].map(s => s.charCodeAt(0)));
}
17 changes: 17 additions & 0 deletions src/date.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/**
* Convert from Date object to unix time.
* Since the UnixTime that can be handled by the Date object is in milliseconds, this method output downscaled to 1/1000.
* @param date The date object. If blank output the current time.
*/
export function dateEncode(date?:Date){
return Math.floor((date ?? new Date()).getTime() / 1000);
}

/**
* Convert from unix time to Date object.
* Since the UnixTime that can be handled by the Date object is in milliseconds, the argument of this method is internally multiplied by x1000.
* @param time The unix time.
*/
export function dateDecode(time:number){
return new Date(time * 1000);
}
14 changes: 7 additions & 7 deletions src/deflate.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
async function convert(data:Uint8Array, ts:TransformStream<Uint8Array, Uint8Array>){
async function streamConvert(data:Uint8Array, ts:TransformStream<Uint8Array, Uint8Array>){
return new Uint8Array(await new Response(new Blob([data]).stream().pipeThrough(ts)).arrayBuffer());
}

/**
* Compresses raw binary in "deflate" format (RFC1951 compliant).
* It does not include header information like "gzip" (RFC1952) or "zlib" (RFC1950) as it does purely "compression only".
* @param data The byte array.
**/
* @param data The byte.
*/
export async function deflateEncode(data:Uint8Array){
return await convert(data, new CompressionStream("deflate-raw"));
return await streamConvert(data, new CompressionStream("deflate-raw"));
}

/**
* Decompress "deflate" format (RFC1951 compliant) binary.
* Binaries containing header information like "gzip" (RFC1952) or "zlib" (RFC1950) cannot be decompressed.
* @param data The byte array.
**/
* @param data The byte.
*/
export async function deflateDecode(data:Uint8Array){
return await convert(data, new DecompressionStream("deflate-raw"));
return await streamConvert(data, new DecompressionStream("deflate-raw"));
}
8 changes: 5 additions & 3 deletions src/fetch.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import {type JsonValue} from "../deps.ts";
export type JsonStruct = string | number | boolean | null | JsonStruct[] | {
[key: string]: JsonStruct;
};

export type QueryInit = Exclude<HeadersInit, Headers> | URLSearchParams;

Expand All @@ -8,7 +10,7 @@ export interface FetchInit extends Omit<RequestInit, "window">{

export interface FetchResponseType{
"text": string;
"json": JsonValue;
"json": JsonStruct;
"form": FormData;
"byte": Uint8Array;
"buffer": ArrayBuffer;
Expand All @@ -21,7 +23,7 @@ export interface FetchResponseType{
* @param path Target URL. Since the query string is ignored, please specify it in the `option.query` property instead of writing it directly in the URL.
* @param type The type you want to receive in the response.
* @param option Fetch option. `window` is removed from `RequestInit` and `query` is added to write the query string.
**/
*/
export async function fetchExtend<T extends keyof FetchResponseType>(path:string, type:T, option?:FetchInit){
const {origin, pathname} = /^http(s|):\/\//i.test(path) ? new URL(path) : new URL(path, location.href);
const query = new URLSearchParams(option?.query).toString();
Expand Down
30 changes: 15 additions & 15 deletions src/minipack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,18 @@ function byte2text(data:Uint8Array){
}

/**
* Convert from array of file object to "minipack" archive format.
* @see [README.md](../README.md)
* @param files Array of file objects.
**/
export async function minipackEncode(files:File[]){
const archive = new Uint8Array(files.reduce((a, {size: s, name: n}) => a + sizeTotal + text2byte(n).byteLength + s, 0));
* Convert from array of name and byte to "minipack" archive format.
* @see https://deno.land/x/simple_utility
* @param files Array of name and byte.
*/
export async function minipackEncode(files:[string, Uint8Array][]){
const archive = new Uint8Array(files.reduce((a, [k, v]) => a + sizeTotal + text2byte(k).byteLength + v.byteLength, 0));

let offset = 0;

for(const file of files){
const name = text2byte(file.name);
const body = new Uint8Array(await file.arrayBuffer());
for(const [k, v] of files){
const name = text2byte(k);
const body = v;

archive.set(await byte2hash(body), offset);
offset += size.hash;
Expand All @@ -52,12 +52,12 @@ export async function minipackEncode(files:File[]){
}

/**
* Convert from binary in "minipack" archive format to file object array.
* @see [README.md](../README.md)
* @param archive The byte array.
**/
* Convert from binary in "minipack" archive format to array of name and byte.
* @see https://deno.land/x/simple_utility
* @param archive The byte.
*/
export async function minipackDecode(archive:Uint8Array){
const files:File[] = [];
const files:[string, Uint8Array][] = [];

let offset = 0;

Expand All @@ -78,7 +78,7 @@ export async function minipackDecode(archive:Uint8Array){
throw new Error();
}

files.push(new File([body], name));
files.push([name, body]);
}

return files;
Expand Down
7 changes: 7 additions & 0 deletions src/text.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/**
* In addition to leading and trailing spaces, tabs, carriage returns, and two or more consecutive spaces are converted to a single space.
* @param data The string.
*/
export function trimExtend(data:string){
return data.trim().replace(/\r/g, "").replace(/\t/g, " ").replace(/ +/g, " ").replace(/ +$/mg, "");
}
24 changes: 24 additions & 0 deletions test/date.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import {assertEquals} from "../deps.test.ts";
import {dateEncode, dateDecode} from "../src/date.ts";

const sample = new Date(2000, 0, 1, 0, 0, 0, 0);

const encodeResult = 946684800;

Deno.test({
name: "Date: Encode.",
async fn(){
const result = await dateEncode(sample);

assertEquals(result, encodeResult);
}
});

Deno.test({
name: "Date: Decode.",
async fn(){
const result = await dateDecode(encodeResult);

assertEquals(result.toISOString(), sample.toISOString());
}
});
11 changes: 6 additions & 5 deletions test/minipack.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ const encodeResult = new Uint8Array([
Deno.test({
name: "Minipack: Encode.",
async fn(){
const result = await minipackEncode([new File([sample], fileName)]);
const result = await minipackEncode([
[fileName, sample]
]);

assertEquals(result, encodeResult);
}
Expand All @@ -26,10 +28,9 @@ Deno.test({
Deno.test({
name: "Minipack: Decode.",
async fn(){
const result = await minipackDecode(encodeResult);
const [[name, body]] = await minipackDecode(encodeResult);

const file = result.at(0);
assertEquals(file?.name, fileName);
assertEquals(new Uint8Array(await file?.arrayBuffer() ?? []), sample);
assertEquals(name, fileName);
assertEquals(body, sample);
}
});
15 changes: 15 additions & 0 deletions test/text.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import {assertEquals} from "../deps.test.ts";
import {trimExtend} from "../src/text.ts";

const sample = " Lorem ipsum\r dolor sit \t amet. ";

const encodeResult = "Lorem ipsum dolor sit amet.";

Deno.test({
name: "Text: Trim.",
async fn(){
const result = await trimExtend(sample);

assertEquals(result, encodeResult);
}
});

0 comments on commit cb3f38d

Please sign in to comment.