diff options
author | Kevin (Kun) "Kassimo" Qian <kevinkassimo@gmail.com> | 2018-09-20 15:53:29 -0700 |
---|---|---|
committer | Ryan Dahl <ry@tinyclouds.org> | 2018-09-20 18:53:29 -0400 |
commit | 4d16d54ff85d84723b8493e6a47caf70becc6660 (patch) | |
tree | 3eff7fdb9c77717e2930a548db374e40f7547279 | |
parent | 52d415537b6b9f6be115dca4daee3f3a36be0ce9 (diff) |
Add atob() and btoa() (#776)
-rw-r--r-- | js/globals.ts | 6 | ||||
-rw-r--r-- | js/text_encoding.ts | 41 | ||||
-rw-r--r-- | js/text_encoding_test.ts | 26 | ||||
-rw-r--r-- | js/unit_tests.ts | 1 |
4 files changed, 74 insertions, 0 deletions
diff --git a/js/globals.ts b/js/globals.ts index 912af7dc4..3e40db06c 100644 --- a/js/globals.ts +++ b/js/globals.ts @@ -25,6 +25,8 @@ declare global { TextEncoder: typeof TextEncoder; TextDecoder: typeof TextDecoder; + atob: typeof atob; + btoa: typeof btoa; Headers: typeof Headers; Blob: typeof Blob; @@ -43,6 +45,8 @@ declare global { // tslint:disable:variable-name const TextEncoder: typeof textEncoding.TextEncoder; const TextDecoder: typeof textEncoding.TextDecoder; + const atob: typeof textEncoding.atob; + const btoa: typeof textEncoding.btoa; const Headers: typeof DenoHeaders; const Blob: typeof DenoBlob; // tslint:enable:variable-name @@ -62,6 +66,8 @@ window.clearInterval = timers.clearTimer; window.console = new Console(libdeno.print); window.TextEncoder = textEncoding.TextEncoder; window.TextDecoder = textEncoding.TextDecoder; +window.atob = textEncoding.atob; +window.btoa = textEncoding.btoa; window.fetch = fetch_.fetch; diff --git a/js/text_encoding.ts b/js/text_encoding.ts index c8e262f5e..087bbc952 100644 --- a/js/text_encoding.ts +++ b/js/text_encoding.ts @@ -1,4 +1,45 @@ // Copyright 2018 the Deno authors. All rights reserved. MIT license. +import * as base64 from "base64-js"; +import { DenoError, ErrorKind } from "./errors"; + +export function atob(s: string): string { + const rem = s.length % 4; + // base64-js requires length exactly times of 4 + if (rem > 0) { + s = s.padEnd(s.length + (4 - rem), "="); + } + let byteArray; + try { + byteArray = base64.toByteArray(s); + } catch (_) { + throw new DenoError( + ErrorKind.InvalidInput, + "The string to be decoded is not correctly encoded" + ); + } + let result = ""; + for (let i = 0; i < byteArray.length; i++) { + result += String.fromCharCode(byteArray[i]); + } + return result; +} + +export function btoa(s: string): string { + const byteArray = []; + for (let i = 0; i < s.length; i++) { + const charCode = s[i].charCodeAt(0); + if (charCode > 0xff) { + throw new DenoError( + ErrorKind.InvalidInput, + "The string to be encoded contains characters " + + "outside of the Latin1 range." + ); + } + byteArray.push(charCode); + } + const result = base64.fromByteArray(Uint8Array.from(byteArray)); + return result; +} // @types/text-encoding relies on lib.dom.d.ts for some interfaces. We do not // want to include lib.dom.d.ts (due to size) into deno's global type scope. diff --git a/js/text_encoding_test.ts b/js/text_encoding_test.ts new file mode 100644 index 000000000..7a9aec833 --- /dev/null +++ b/js/text_encoding_test.ts @@ -0,0 +1,26 @@ +// Copyright 2018 the Deno authors. All rights reserved. MIT license. +import { test, assert, assertEqual } from "./test_util.ts"; + +test(function atobSuccess() { + const text = "hello world"; + const encoded = btoa(text); + assertEqual(encoded, "aGVsbG8gd29ybGQ="); +}); + +test(function btoaSuccess() { + const encoded = "aGVsbG8gd29ybGQ="; + const decoded = atob(encoded); + assertEqual(decoded, "hello world"); +}); + +test(function btoaFailed() { + const text = "你好"; + let err; + try { + btoa(text); + } catch (e) { + err = e; + } + assert(!!err); + assertEqual(err.name, "InvalidInput"); +}); diff --git a/js/unit_tests.ts b/js/unit_tests.ts index a535aea55..9b85cf3ec 100644 --- a/js/unit_tests.ts +++ b/js/unit_tests.ts @@ -15,3 +15,4 @@ import "./blob_test.ts"; import "./timers_test.ts"; import "./symlink_test.ts"; import "./platform_test.ts"; +import "./text_encoding_test.ts"; |