mirror of
https://github.com/swc-project/swc.git
synced 2024-11-27 13:38:33 +03:00
fix(bundler): Fix bugs (#1437)
swc_bundler: - [x] Fix wrapped esms. (denoland/deno#9307) - [x] Make test secure.
This commit is contained in:
parent
eec65f25bb
commit
bbaf619f63
@ -9,7 +9,7 @@ include = ["Cargo.toml", "build.rs", "src/**/*.rs", "src/**/*.js"]
|
||||
license = "Apache-2.0/MIT"
|
||||
name = "swc_bundler"
|
||||
repository = "https://github.com/swc-project/swc.git"
|
||||
version = "0.25.1"
|
||||
version = "0.25.2"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
[features]
|
||||
|
5
bundler/scripts/download.sh
Executable file
5
bundler/scripts/download.sh
Executable file
@ -0,0 +1,5 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
export CI=1
|
||||
cargo test --test fixture
|
||||
cargo test --test deno
|
@ -1,8 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eux
|
||||
|
||||
cargo test --no-run
|
||||
|
||||
cargo test --lib
|
||||
cargo test --test fixture
|
||||
(cd ../spack && cargo test --test fixture)
|
||||
|
@ -8,7 +8,7 @@ use swc_atoms::js_word;
|
||||
use swc_common::{SyntaxContext, DUMMY_SP};
|
||||
use swc_ecma_ast::*;
|
||||
use swc_ecma_utils::{find_ids, private_ident, ExprFactory};
|
||||
use swc_ecma_visit::{noop_fold_type, noop_visit_type, Fold, FoldWith, Node, Visit};
|
||||
use swc_ecma_visit::{noop_fold_type, noop_visit_type, Fold, Node, Visit};
|
||||
|
||||
impl<L, R> Bundler<'_, L, R>
|
||||
where
|
||||
@ -35,7 +35,7 @@ where
|
||||
&self,
|
||||
ctx: &Ctx,
|
||||
id: ModuleId,
|
||||
mut module: Modules,
|
||||
module: Modules,
|
||||
) -> Result<Modules, Error> {
|
||||
let span = DUMMY_SP;
|
||||
let info = self.scope.get_module(id).unwrap();
|
||||
@ -44,7 +44,6 @@ where
|
||||
None => bail!("{:?} should not be wrapped with a function", id),
|
||||
};
|
||||
let injected_ctxt = self.injected_ctxt;
|
||||
module.sort(id, &ctx.graph, &self.cm);
|
||||
|
||||
let is_async = {
|
||||
let mut v = TopLevelAwaitFinder { found: false };
|
||||
@ -52,93 +51,89 @@ where
|
||||
v.found
|
||||
};
|
||||
|
||||
let mut module_items = vec![];
|
||||
let mut addtional_items = vec![];
|
||||
|
||||
let stmts = {
|
||||
module.iter().for_each(|(_, item)| {
|
||||
match item {
|
||||
// Handle `export *`-s from dependency modules.
|
||||
//
|
||||
// See: https://github.com/denoland/deno/issues/9200
|
||||
ModuleItem::ModuleDecl(ModuleDecl::ExportNamed(NamedExport {
|
||||
span,
|
||||
ref specifiers,
|
||||
..
|
||||
})) if span.ctxt == injected_ctxt => {
|
||||
for s in specifiers {
|
||||
match s {
|
||||
ExportSpecifier::Named(ExportNamedSpecifier {
|
||||
orig,
|
||||
exported: Some(exported),
|
||||
..
|
||||
}) => {
|
||||
if let Some(..) = ctx.transitive_remap.get(&exported.span.ctxt)
|
||||
{
|
||||
let mut var_name = exported.clone();
|
||||
var_name.span.ctxt = info.export_ctxt();
|
||||
module_items.push(
|
||||
exported
|
||||
.clone()
|
||||
.assign_to(var_name.clone())
|
||||
.into_module_item(
|
||||
injected_ctxt,
|
||||
"export * in a wrapped esm",
|
||||
),
|
||||
);
|
||||
let specifier =
|
||||
ExportSpecifier::Named(ExportNamedSpecifier {
|
||||
span: DUMMY_SP,
|
||||
orig: orig.clone(),
|
||||
exported: Some(exported.clone()),
|
||||
});
|
||||
module_items.push(ModuleItem::ModuleDecl(
|
||||
ModuleDecl::ExportNamed(NamedExport {
|
||||
module.iter().for_each(|(module_id, item)| {
|
||||
match item {
|
||||
// Handle `export *`-s from dependency modules.
|
||||
//
|
||||
// See: https://github.com/denoland/deno/issues/9200
|
||||
ModuleItem::ModuleDecl(ModuleDecl::ExportNamed(NamedExport {
|
||||
span,
|
||||
ref specifiers,
|
||||
..
|
||||
})) if span.ctxt == injected_ctxt => {
|
||||
for s in specifiers {
|
||||
match s {
|
||||
ExportSpecifier::Named(ExportNamedSpecifier {
|
||||
orig,
|
||||
exported: Some(exported),
|
||||
..
|
||||
}) => {
|
||||
if let Some(..) = ctx.transitive_remap.get(&exported.span.ctxt) {
|
||||
let mut var_name = exported.clone();
|
||||
var_name.span.ctxt = info.export_ctxt();
|
||||
addtional_items.push((
|
||||
module_id,
|
||||
exported
|
||||
.clone()
|
||||
.assign_to(var_name.clone())
|
||||
.into_module_item(
|
||||
injected_ctxt,
|
||||
"export * in a wrapped esm",
|
||||
),
|
||||
));
|
||||
let specifier = ExportSpecifier::Named(ExportNamedSpecifier {
|
||||
span: DUMMY_SP,
|
||||
orig: orig.clone(),
|
||||
exported: Some(exported.clone()),
|
||||
});
|
||||
addtional_items.push((
|
||||
module_id,
|
||||
ModuleItem::ModuleDecl(ModuleDecl::ExportNamed(
|
||||
NamedExport {
|
||||
span: DUMMY_SP.with_ctxt(injected_ctxt),
|
||||
specifiers: vec![specifier],
|
||||
src: None,
|
||||
type_only: false,
|
||||
asserts: None,
|
||||
}),
|
||||
));
|
||||
}
|
||||
},
|
||||
)),
|
||||
));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
});
|
||||
_ => {}
|
||||
}
|
||||
});
|
||||
|
||||
let mut module = Module::from(module).fold_with(&mut ExportToReturn {
|
||||
synthesized_ctxt: self.synthesized_ctxt,
|
||||
return_props: Default::default(),
|
||||
});
|
||||
|
||||
take(&mut module.body)
|
||||
.into_iter()
|
||||
.filter_map(|v| match v {
|
||||
ModuleItem::Stmt(s @ Stmt::Return(..)) => Some(s),
|
||||
|
||||
ModuleItem::Stmt(s) => {
|
||||
module_items.push(ModuleItem::Stmt(s));
|
||||
None
|
||||
}
|
||||
|
||||
ModuleItem::ModuleDecl(ModuleDecl::ExportAll(ref export)) => {
|
||||
// We handle this later.
|
||||
let mut map = ctx.export_stars_in_wrapped.lock();
|
||||
map.entry(id).or_default().push(export.span.ctxt);
|
||||
module_items.push(v);
|
||||
None
|
||||
}
|
||||
_ => {
|
||||
module_items.push(v);
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
let mut export_visitor = ExportToReturn {
|
||||
synthesized_ctxt: self.synthesized_ctxt,
|
||||
return_props: Default::default(),
|
||||
};
|
||||
let mut module = module.fold_with(&mut export_visitor);
|
||||
|
||||
module.append_all(addtional_items);
|
||||
|
||||
let return_stmt = Stmt::Return(ReturnStmt {
|
||||
span: DUMMY_SP,
|
||||
arg: Some(Box::new(Expr::Object(ObjectLit {
|
||||
span: DUMMY_SP,
|
||||
props: take(&mut export_visitor.return_props),
|
||||
}))),
|
||||
});
|
||||
|
||||
module.iter().for_each(|(_, v)| match v {
|
||||
ModuleItem::ModuleDecl(ModuleDecl::ExportAll(ref export)) => {
|
||||
// We handle this later.
|
||||
let mut map = ctx.export_stars_in_wrapped.lock();
|
||||
map.entry(id).or_default().push(export.span.ctxt);
|
||||
}
|
||||
_ => {}
|
||||
});
|
||||
|
||||
let module_fn = Expr::Fn(FnExpr {
|
||||
function: Function {
|
||||
@ -147,7 +142,7 @@ where
|
||||
span: DUMMY_SP,
|
||||
body: Some(BlockStmt {
|
||||
span: DUMMY_SP,
|
||||
stmts,
|
||||
stmts: vec![return_stmt],
|
||||
}),
|
||||
is_generator: false,
|
||||
is_async,
|
||||
@ -183,7 +178,7 @@ where
|
||||
}],
|
||||
};
|
||||
|
||||
module_items.push(ModuleItem::Stmt(Stmt::Decl(Decl::Var(var_decl))));
|
||||
module.append(id, ModuleItem::Stmt(Stmt::Decl(Decl::Var(var_decl))));
|
||||
|
||||
// print_hygiene(
|
||||
// "wrap",
|
||||
@ -195,15 +190,7 @@ where
|
||||
// },
|
||||
// );
|
||||
|
||||
Ok(Modules::from(
|
||||
id,
|
||||
Module {
|
||||
span: DUMMY_SP,
|
||||
shebang: None,
|
||||
body: module_items,
|
||||
},
|
||||
self.injected_ctxt,
|
||||
))
|
||||
Ok(module)
|
||||
}
|
||||
}
|
||||
|
||||
@ -229,16 +216,19 @@ struct ExportToReturn {
|
||||
}
|
||||
|
||||
impl ExportToReturn {
|
||||
fn export_id(&mut self, i: Ident) {
|
||||
fn export_id(&mut self, mut i: Ident) {
|
||||
i.span.ctxt = SyntaxContext::empty();
|
||||
self.return_props
|
||||
.push(PropOrSpread::Prop(Box::new(Prop::Shorthand(i.clone()))));
|
||||
.push(PropOrSpread::Prop(Box::new(Prop::Shorthand(i))));
|
||||
}
|
||||
|
||||
fn export_key_value(&mut self, key: Ident, value: Ident) {
|
||||
fn export_key_value(&mut self, mut key: Ident, value: Ident) {
|
||||
key.span.ctxt = SyntaxContext::empty();
|
||||
|
||||
self.return_props
|
||||
.push(PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp {
|
||||
key: PropName::Ident(key.clone()),
|
||||
value: Box::new(Expr::Ident(value.clone())),
|
||||
key: PropName::Ident(key),
|
||||
value: Box::new(Expr::Ident(value)),
|
||||
}))));
|
||||
}
|
||||
}
|
||||
@ -346,23 +336,4 @@ impl Fold for ExportToReturn {
|
||||
ModuleItem::Stmt(Stmt::Empty(EmptyStmt { span: DUMMY_SP }))
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_module_items(&mut self, items: Vec<ModuleItem>) -> Vec<ModuleItem> {
|
||||
let mut new = items.fold_children_with(self);
|
||||
|
||||
new.retain(|s| match s {
|
||||
ModuleItem::Stmt(Stmt::Empty(..)) => false,
|
||||
_ => true,
|
||||
});
|
||||
|
||||
new.push(ModuleItem::Stmt(Stmt::Return(ReturnStmt {
|
||||
span: DUMMY_SP,
|
||||
arg: Some(Box::new(Expr::Object(ObjectLit {
|
||||
span: DUMMY_SP,
|
||||
props: take(&mut self.return_props),
|
||||
}))),
|
||||
})));
|
||||
|
||||
new
|
||||
}
|
||||
}
|
||||
|
@ -117,12 +117,9 @@ where
|
||||
});
|
||||
} else {
|
||||
dep = dep.fold_with(&mut DepUnexporter {});
|
||||
|
||||
// print_hygiene(&format!("dep: unexport"), &self.cm,
|
||||
// &dep.clone().into());
|
||||
}
|
||||
|
||||
// TODO: Add varaible based on specifers
|
||||
// print_hygiene(&format!("done: reexport"), &self.cm, &dep.clone().into());
|
||||
|
||||
Ok(dep)
|
||||
})
|
||||
|
@ -143,7 +143,11 @@ where
|
||||
}
|
||||
};
|
||||
|
||||
// print_hygiene("wrapped: before deps", &self.cm, &module);
|
||||
// print_hygiene(
|
||||
// &format!("wrapped: before deps: {:?}", dep_id),
|
||||
// &self.cm,
|
||||
// &module.clone().into(),
|
||||
// );
|
||||
|
||||
if let Some(plan) = ctx.plan.circular.get(&dep_id) {
|
||||
module = self
|
||||
@ -155,6 +159,12 @@ where
|
||||
.merge_deps(ctx, false, module, plan, &dep_info, false)
|
||||
.context("failed to merge dependencies")?;
|
||||
|
||||
// print_hygiene(
|
||||
// &format!("wrapped: after deps: {:?}", dep_id),
|
||||
// &self.cm,
|
||||
// &module.clone().into(),
|
||||
// );
|
||||
|
||||
// This code is currently not required because wrapped es modules store their
|
||||
// content on the top scope.
|
||||
//
|
||||
@ -183,6 +193,12 @@ where
|
||||
} else {
|
||||
let mut module = self.merge_modules(ctx, dep_id, false, true)?;
|
||||
|
||||
// print_hygiene(
|
||||
// &format!("not-wrapped: after deps: {:?}", dep_id),
|
||||
// &self.cm,
|
||||
// &module.clone().into(),
|
||||
// );
|
||||
|
||||
// print_hygiene(
|
||||
// &format!(
|
||||
// "import: Before handle_import_deps {:?}:{:?}",
|
||||
@ -409,6 +425,8 @@ where
|
||||
source.unwrap().clone(),
|
||||
);
|
||||
|
||||
// print_hygiene("merged as reexport", &self.cm, &module.clone().into());
|
||||
|
||||
log::debug!(
|
||||
"Merged {} into {} as a reexport",
|
||||
dep_info.fm.name,
|
||||
@ -1074,7 +1092,6 @@ where
|
||||
|
||||
new.push(ModuleItem::Stmt(Stmt::Decl(Decl::Var(v))));
|
||||
|
||||
log::trace!("Exporting `default` with `export decl``");
|
||||
let export =
|
||||
ModuleItem::ModuleDecl(ModuleDecl::ExportNamed(NamedExport {
|
||||
span: export.span.with_ctxt(injected_ctxt),
|
||||
@ -1086,6 +1103,12 @@ where
|
||||
id.span.with_ctxt(info.export_ctxt()),
|
||||
);
|
||||
|
||||
log::trace!(
|
||||
"Exporting `{}{:?}` with `export decl`",
|
||||
id.sym,
|
||||
id.span.ctxt
|
||||
);
|
||||
|
||||
new.push(
|
||||
id.clone()
|
||||
.assign_to(exported.clone())
|
||||
|
@ -1033,3 +1033,63 @@ fn deno_8302_3() {
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deno_9307_1() {
|
||||
suite()
|
||||
.file(
|
||||
"main.js",
|
||||
"
|
||||
export * as G from './a';
|
||||
",
|
||||
)
|
||||
.file("a.js", "")
|
||||
.run(|t| {
|
||||
let module = t
|
||||
.bundler
|
||||
.load_transformed(&FileName::Real("main.js".into()))?
|
||||
.unwrap();
|
||||
let mut entries = AHashMap::default();
|
||||
entries.insert("main.js".to_string(), module.clone());
|
||||
|
||||
let p = t.bundler.calculate_plan(entries)?;
|
||||
|
||||
dbg!(&p);
|
||||
|
||||
assert_normal(t, &p.0, "main", &["a"]);
|
||||
|
||||
assert_normal(t, &p.0, "a", &[]);
|
||||
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deno_9307_2() {
|
||||
suite()
|
||||
.file(
|
||||
"main.js",
|
||||
"
|
||||
export * from './a';
|
||||
",
|
||||
)
|
||||
.file("a.js", "")
|
||||
.run(|t| {
|
||||
let module = t
|
||||
.bundler
|
||||
.load_transformed(&FileName::Real("main.js".into()))?
|
||||
.unwrap();
|
||||
let mut entries = AHashMap::default();
|
||||
entries.insert("main.js".to_string(), module.clone());
|
||||
|
||||
let p = t.bundler.calculate_plan(entries)?;
|
||||
|
||||
dbg!(&p);
|
||||
|
||||
assert_normal(t, &p.0, "main", &["a"]);
|
||||
|
||||
assert_normal(t, &p.0, "a", &[]);
|
||||
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
|
@ -27,6 +27,10 @@ pub(crate) fn inline(injected_ctxt: SyntaxContext, module: &mut Modules) {
|
||||
|
||||
module.visit_with(&mut v);
|
||||
module.visit_mut_with(&mut v);
|
||||
module.retain_mut(|_, s| match s {
|
||||
ModuleItem::Stmt(Stmt::Empty(..)) => false,
|
||||
_ => true,
|
||||
});
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -0,0 +1,68 @@
|
||||
// Loaded from https://deno.land/std/fs/ensure_file.ts
|
||||
|
||||
|
||||
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
|
||||
import * as path from "../path/mod.ts";
|
||||
import { ensureDir, ensureDirSync } from "./ensure_dir.ts";
|
||||
import { getFileInfoType } from "./_util.ts";
|
||||
|
||||
/**
|
||||
* Ensures that the file exists.
|
||||
* If the file that is requested to be created is in directories that do not
|
||||
* exist.
|
||||
* these directories are created. If the file already exists,
|
||||
* it is NOTMODIFIED.
|
||||
* Requires the `--allow-read` and `--allow-write` flag.
|
||||
*/
|
||||
export async function ensureFile(filePath: string): Promise<void> {
|
||||
try {
|
||||
// if file exists
|
||||
const stat = await Deno.lstat(filePath);
|
||||
if (!stat.isFile) {
|
||||
throw new Error(
|
||||
`Ensure path exists, expected 'file', got '${getFileInfoType(stat)}'`,
|
||||
);
|
||||
}
|
||||
} catch (err) {
|
||||
// if file not exists
|
||||
if (err instanceof Deno.errors.NotFound) {
|
||||
// ensure dir exists
|
||||
await ensureDir(path.dirname(filePath));
|
||||
// create file
|
||||
await Deno.writeFile(filePath, new Uint8Array());
|
||||
return;
|
||||
}
|
||||
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the file exists.
|
||||
* If the file that is requested to be created is in directories that do not
|
||||
* exist,
|
||||
* these directories are created. If the file already exists,
|
||||
* it is NOT MODIFIED.
|
||||
* Requires the `--allow-read` and `--allow-write` flag.
|
||||
*/
|
||||
export function ensureFileSync(filePath: string): void {
|
||||
try {
|
||||
// if file exists
|
||||
const stat = Deno.lstatSync(filePath);
|
||||
if (!stat.isFile) {
|
||||
throw new Error(
|
||||
`Ensure path exists, expected 'file', got '${getFileInfoType(stat)}'`,
|
||||
);
|
||||
}
|
||||
} catch (err) {
|
||||
// if file not exists
|
||||
if (err instanceof Deno.errors.NotFound) {
|
||||
// ensure dir exists
|
||||
ensureDirSync(path.dirname(filePath));
|
||||
// create file
|
||||
Deno.writeFileSync(filePath, new Uint8Array());
|
||||
return;
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
// Loaded from https://deno.land/x/god_crypto@v0.2.0/src/rsa.ts
|
||||
|
||||
|
||||
import { power_mod } from "./math.ts";
|
||||
import { eme_oaep_encode, eme_oaep_decode } from "./eme_oaep.ts";
|
||||
import { os2ip, i2osp } from "./primitives.ts";
|
||||
import { concat, random_bytes } from "./helper.ts";
|
||||
|
||||
/**
|
||||
* @param n public key modulus
|
||||
* @param e public key exponent
|
||||
* @param m message representative
|
||||
*/
|
||||
export function rsaep(n: bigint, e: bigint, m: bigint): bigint {
|
||||
return power_mod(m, e, n);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param n private key modulus
|
||||
* @param d private key exponent
|
||||
* @param c ciphertext representative
|
||||
*/
|
||||
export function rsadp(n: bigint, d: bigint, c: bigint): bigint {
|
||||
return power_mod(c, d, n);
|
||||
}
|
||||
|
||||
export function rsa_oaep_encrypt(bytes: number, n: bigint, e: bigint, m: Uint8Array, algorithm: "sha1" | "sha256") {
|
||||
const em = eme_oaep_encode(new Uint8Array(0), m, bytes, algorithm);
|
||||
const msg = os2ip(em);
|
||||
const c = rsaep(n, e, msg);
|
||||
return i2osp(c, bytes);
|
||||
}
|
||||
|
||||
export function rsa_oaep_decrypt(bytes: number, n: bigint, d: bigint, c: Uint8Array, algorithm: "sha1" | "sha256") {
|
||||
const em = rsadp(n, d, os2ip(c));
|
||||
const m = eme_oaep_decode(new Uint8Array(0), i2osp(em, bytes), bytes, algorithm);
|
||||
return m;
|
||||
}
|
||||
|
||||
export function rsa_pkcs1_encrypt(bytes: number, n: bigint, e: bigint, m: Uint8Array) {
|
||||
const p = concat([0x00, 0x02], random_bytes(bytes - m.length - 3), [0x00], m);
|
||||
const msg = os2ip(p);
|
||||
const c = rsaep(n, e, msg);
|
||||
return i2osp(c, bytes);
|
||||
}
|
||||
|
||||
export function rsa_pkcs1_decrypt(bytes: number, n: bigint, d: bigint, c: Uint8Array) {
|
||||
const em = i2osp(rsadp(n, d, os2ip(c)), bytes);
|
||||
|
||||
if (em[0] !== 0) throw "Decryption error";
|
||||
if (em[1] !== 0x02) throw "Decryption error";
|
||||
|
||||
let psCursor = 2;
|
||||
for(; psCursor < em.length; psCursor++) {
|
||||
if (em[psCursor] === 0x00) break;
|
||||
}
|
||||
|
||||
if (psCursor < 10) throw "Decryption error";
|
||||
|
||||
return em.slice(psCursor + 1);
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
// Loaded from https://deno.land/x/deno_image@v0.0.3/lib/decoders/fast-png/common.ts
|
||||
|
||||
|
||||
export const pngSignature = [137, 80, 78, 71, 13, 10, 26, 10];
|
||||
|
||||
const crcTable: number[] = [];
|
||||
for (let n = 0; n < 256; n++) {
|
||||
let c = n;
|
||||
for (let k = 0; k < 8; k++) {
|
||||
if (c & 1) {
|
||||
c = 0xedb88320 ^ (c >>> 1);
|
||||
} else {
|
||||
c = c >>> 1;
|
||||
}
|
||||
}
|
||||
crcTable[n] = c;
|
||||
}
|
||||
|
||||
const initialCrc = 0xffffffff;
|
||||
function updateCrc(
|
||||
currentCrc: number,
|
||||
data: Uint8Array,
|
||||
length: number,
|
||||
): number {
|
||||
let c = currentCrc;
|
||||
for (let n = 0; n < length; n++) {
|
||||
c = crcTable[(c ^ data[n]) & 0xff] ^ (c >>> 8);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
export function crc(data: Uint8Array, length: number): number {
|
||||
return (updateCrc(initialCrc, data, length) ^ initialCrc) >>> 0;
|
||||
}
|
@ -0,0 +1,114 @@
|
||||
// Loaded from https://deno.land/std/encoding/hex.ts
|
||||
|
||||
|
||||
// Ported from Go
|
||||
// https://github.com/golang/go/blob/go1.12.5/src/encoding/hex/hex.go
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
const hexTable = new TextEncoder().encode("0123456789abcdef");
|
||||
|
||||
/**
|
||||
* ErrInvalidByte takes an invalid byte and returns an Error.
|
||||
* @param byte
|
||||
*/
|
||||
export function errInvalidByte(byte: number): Error {
|
||||
return new Error(
|
||||
"encoding/hex: invalid byte: " +
|
||||
new TextDecoder().decode(new Uint8Array([byte])),
|
||||
);
|
||||
}
|
||||
|
||||
/** ErrLength returns an error about odd string length. */
|
||||
export function errLength(): Error {
|
||||
return new Error("encoding/hex: odd length hex string");
|
||||
}
|
||||
|
||||
// fromHexChar converts a hex character into its value.
|
||||
function fromHexChar(byte: number): number {
|
||||
// '0' <= byte && byte <= '9'
|
||||
if (48 <= byte && byte <= 57) return byte - 48;
|
||||
// 'a' <= byte && byte <= 'f'
|
||||
if (97 <= byte && byte <= 102) return byte - 97 + 10;
|
||||
// 'A' <= byte && byte <= 'F'
|
||||
if (65 <= byte && byte <= 70) return byte - 65 + 10;
|
||||
|
||||
throw errInvalidByte(byte);
|
||||
}
|
||||
|
||||
/**
|
||||
* EncodedLen returns the length of an encoding of n source bytes. Specifically,
|
||||
* it returns n * 2.
|
||||
* @param n
|
||||
*/
|
||||
export function encodedLen(n: number): number {
|
||||
return n * 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode encodes `src` into `encodedLen(src.length)` bytes.
|
||||
* @param src
|
||||
*/
|
||||
export function encode(src: Uint8Array): Uint8Array {
|
||||
const dst = new Uint8Array(encodedLen(src.length));
|
||||
for (let i = 0; i < dst.length; i++) {
|
||||
const v = src[i];
|
||||
dst[i * 2] = hexTable[v >> 4];
|
||||
dst[i * 2 + 1] = hexTable[v & 0x0f];
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
/**
|
||||
* EncodeToString returns the hexadecimal encoding of `src`.
|
||||
* @param src
|
||||
*/
|
||||
export function encodeToString(src: Uint8Array): string {
|
||||
return new TextDecoder().decode(encode(src));
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode decodes `src` into `decodedLen(src.length)` bytes
|
||||
* If the input is malformed an error will be thrown
|
||||
* the error.
|
||||
* @param src
|
||||
*/
|
||||
export function decode(src: Uint8Array): Uint8Array {
|
||||
const dst = new Uint8Array(decodedLen(src.length));
|
||||
for (let i = 0; i < dst.length; i++) {
|
||||
const a = fromHexChar(src[i * 2]);
|
||||
const b = fromHexChar(src[i * 2 + 1]);
|
||||
dst[i] = (a << 4) | b;
|
||||
}
|
||||
|
||||
if (src.length % 2 == 1) {
|
||||
// Check for invalid char before reporting bad length,
|
||||
// since the invalid char (if present) is an earlier problem.
|
||||
fromHexChar(src[dst.length * 2]);
|
||||
throw errLength();
|
||||
}
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
/**
|
||||
* DecodedLen returns the length of decoding `x` source bytes.
|
||||
* Specifically, it returns `x / 2`.
|
||||
* @param x
|
||||
*/
|
||||
export function decodedLen(x: number): number {
|
||||
return x >>> 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* DecodeString returns the bytes represented by the hexadecimal string `s`.
|
||||
* DecodeString expects that src contains only hexadecimal characters and that
|
||||
* src has even length.
|
||||
* If the input is malformed, DecodeString will throw an error.
|
||||
* @param s the `string` to decode to `Uint8Array`
|
||||
*/
|
||||
export function decodeString(s: string): Uint8Array {
|
||||
return decode(new TextEncoder().encode(s));
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
// Loaded from https://deno.land/std@0.85.0/io/mod.ts
|
||||
|
||||
|
||||
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
|
||||
export * from "./bufio.ts";
|
||||
export * from "./ioutil.ts";
|
||||
export * from "./readers.ts";
|
||||
export * from "./writers.ts";
|
||||
export * from "./streams.ts";
|
@ -0,0 +1,16 @@
|
||||
// Loaded from https://deno.land/x/segno@v1.1.0/lib/validations/isBtcAddress.ts
|
||||
|
||||
|
||||
// @ts-ignore allowing typedoc to build
|
||||
import { assertString } from '../helpers/assertString.ts';
|
||||
|
||||
// supports Bech32 addresses
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
const btc = /^(bc1|[13])[a-zA-HJ-NP-Z0-9]{25,39}$/;
|
||||
|
||||
export const isBtcAddress = (str: string) => {
|
||||
assertString(str);
|
||||
return btc.test(str);
|
||||
};
|
@ -0,0 +1,21 @@
|
||||
// Loaded from https://deno.land/std@0.79.0/_util/os.ts
|
||||
|
||||
|
||||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
// This module is browser compatible.
|
||||
|
||||
export const osType = (() => {
|
||||
if (globalThis.Deno != null) {
|
||||
return Deno.build.os;
|
||||
}
|
||||
|
||||
// deno-lint-ignore no-explicit-any
|
||||
const navigator = (globalThis as any).navigator;
|
||||
if (navigator?.appVersion?.includes?.("Win") ?? false) {
|
||||
return "windows";
|
||||
}
|
||||
|
||||
return "linux";
|
||||
})();
|
||||
|
||||
export const isWindows = osType === "windows";
|
@ -0,0 +1,36 @@
|
||||
// Loaded from https://deno.land/x/graphql_deno@v15.0.0/lib/validation/rules/UniqueArgumentNamesRule.js
|
||||
|
||||
|
||||
import { GraphQLError } from '../../error/GraphQLError.js';
|
||||
|
||||
/**
|
||||
* Unique argument names
|
||||
*
|
||||
* A GraphQL field or directive is only valid if all supplied arguments are
|
||||
* uniquely named.
|
||||
*/
|
||||
export function UniqueArgumentNamesRule(context) {
|
||||
let knownArgNames = Object.create(null);
|
||||
return {
|
||||
Field() {
|
||||
knownArgNames = Object.create(null);
|
||||
},
|
||||
|
||||
Directive() {
|
||||
knownArgNames = Object.create(null);
|
||||
},
|
||||
|
||||
Argument(node) {
|
||||
const argName = node.name.value;
|
||||
|
||||
if (knownArgNames[argName]) {
|
||||
context.reportError(new GraphQLError(`There can be only one argument named "${argName}".`, [knownArgNames[argName], node.name]));
|
||||
} else {
|
||||
knownArgNames[argName] = node.name;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
// Loaded from https://deno.land/std@0.74.0/fs/exists.ts
|
||||
|
||||
|
||||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
/**
|
||||
* Test whether or not the given path exists by checking with the file system
|
||||
*/
|
||||
export async function exists(filePath: string): Promise<boolean> {
|
||||
try {
|
||||
await Deno.lstat(filePath);
|
||||
return true;
|
||||
} catch (err) {
|
||||
if (err instanceof Deno.errors.NotFound) {
|
||||
return false;
|
||||
}
|
||||
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test whether or not the given path exists by checking with the file system
|
||||
*/
|
||||
export function existsSync(filePath: string): boolean {
|
||||
try {
|
||||
Deno.lstatSync(filePath);
|
||||
return true;
|
||||
} catch (err) {
|
||||
if (err instanceof Deno.errors.NotFound) {
|
||||
return false;
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
// Loaded from https://deno.land/x/ramda@v0.27.2/mod.ts
|
||||
|
||||
|
||||
export * from "./source/index.js";
|
@ -0,0 +1,49 @@
|
||||
// Loaded from https://deno.land/x/deno_image@v0.0.3/lib/decoders/fast-png/pako/lib/zlib/adler32.js
|
||||
|
||||
|
||||
// Note: adler32 takes 12% for level 0 and 2% for level 6.
|
||||
// It isn't worth it to make additional optimizations as in original.
|
||||
// Small size is preferable.
|
||||
|
||||
// (C) 1995-2013 Jean-loup Gailly and Mark Adler
|
||||
// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
export function adler32(adler, buf, len, pos) {
|
||||
var s1 = (adler & 0xffff) |0,
|
||||
s2 = ((adler >>> 16) & 0xffff) |0,
|
||||
n = 0;
|
||||
|
||||
while (len !== 0) {
|
||||
// Set limit ~ twice less than 5552, to keep
|
||||
// s2 in 31-bits, because we force signed ints.
|
||||
// in other case %= will fail.
|
||||
n = len > 2000 ? 2000 : len;
|
||||
len -= n;
|
||||
|
||||
do {
|
||||
s1 = (s1 + buf[pos++]) |0;
|
||||
s2 = (s2 + s1) |0;
|
||||
} while (--n);
|
||||
|
||||
s1 %= 65521;
|
||||
s2 %= 65521;
|
||||
}
|
||||
|
||||
return (s1 | (s2 << 16)) |0;
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
// Loaded from https://deno.land/x/ramda@v0.27.2/source/internal/_isRegExp.js
|
||||
|
||||
|
||||
export default function _isRegExp(x) {
|
||||
return Object.prototype.toString.call(x) === '[object RegExp]';
|
||||
}
|
@ -0,0 +1,110 @@
|
||||
// Loaded from https://deno.land/x/djwt@v1.9/_signature.ts
|
||||
|
||||
|
||||
import type { Algorithm } from "./_algorithm.ts";
|
||||
import {
|
||||
base64url,
|
||||
convertHexToUint8Array,
|
||||
HmacSha256,
|
||||
HmacSha512,
|
||||
RSA,
|
||||
} from "./_depts.ts";
|
||||
|
||||
function assertNever(alg: never, message: string): never {
|
||||
throw new RangeError(message);
|
||||
}
|
||||
|
||||
export function convertHexToBase64url(input: string): string {
|
||||
return base64url.encode(convertHexToUint8Array(input));
|
||||
}
|
||||
|
||||
/**
|
||||
* Do a constant time string comparison. Always compare the complete strings
|
||||
* against each other to get a constant time. This method does not short-cut
|
||||
* if the two string's length differs.
|
||||
* CREDIT: https://github.com/Bruce17/safe-compare
|
||||
*/
|
||||
function safeCompare(a: string, b: string) {
|
||||
const strA = String(a);
|
||||
const lenA = strA.length;
|
||||
let strB = String(b);
|
||||
let result = 0;
|
||||
|
||||
if (lenA !== strB.length) {
|
||||
strB = strA;
|
||||
result = 1;
|
||||
}
|
||||
|
||||
for (var i = 0; i < lenA; i++) {
|
||||
result |= (strA.charCodeAt(i) ^ strB.charCodeAt(i));
|
||||
}
|
||||
|
||||
return result === 0;
|
||||
}
|
||||
|
||||
async function encrypt(
|
||||
algorithm: Algorithm,
|
||||
key: string,
|
||||
message: string,
|
||||
): Promise<string> {
|
||||
switch (algorithm) {
|
||||
case "none":
|
||||
return "";
|
||||
case "HS256":
|
||||
return new HmacSha256(key).update(message).toString();
|
||||
case "HS512":
|
||||
return new HmacSha512(key).update(message).toString();
|
||||
case "RS256":
|
||||
return (
|
||||
await new RSA(RSA.parseKey(key)).sign(message, { hash: "sha256" })
|
||||
).hex();
|
||||
default:
|
||||
assertNever(
|
||||
algorithm,
|
||||
"no matching crypto algorithm in the header: " + algorithm,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export async function create(
|
||||
algorithm: Algorithm,
|
||||
key: string,
|
||||
input: string,
|
||||
): Promise<string> {
|
||||
return convertHexToBase64url(await encrypt(algorithm, key, input));
|
||||
}
|
||||
|
||||
export async function verify({
|
||||
signature,
|
||||
key,
|
||||
algorithm,
|
||||
signingInput,
|
||||
}: {
|
||||
signature: string;
|
||||
key: string;
|
||||
algorithm: Algorithm;
|
||||
signingInput: string;
|
||||
}): Promise<boolean> {
|
||||
switch (algorithm) {
|
||||
case "none":
|
||||
case "HS256":
|
||||
case "HS512": {
|
||||
return safeCompare(
|
||||
signature,
|
||||
(await encrypt(algorithm, key, signingInput)),
|
||||
);
|
||||
}
|
||||
case "RS256": {
|
||||
return await new RSA(RSA.parseKey(key)).verify(
|
||||
convertHexToUint8Array(signature),
|
||||
signingInput,
|
||||
{ hash: "sha256" },
|
||||
);
|
||||
}
|
||||
default:
|
||||
assertNever(
|
||||
algorithm,
|
||||
"no matching crypto algorithm in the header: " + algorithm,
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
// Loaded from https://deno.land/x/graphql_deno@v15.0.0/lib/subscription/index.js
|
||||
|
||||
|
||||
export { subscribe, createSourceEventStream } from './subscribe.js';
|
@ -0,0 +1,8 @@
|
||||
// Loaded from https://deno.land/x/case/paramCase.ts
|
||||
|
||||
|
||||
import normalCase from "./normalCase.ts";
|
||||
|
||||
export default function paramCase(value: string, locale?: string): string {
|
||||
return normalCase(value, locale, "-");
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
// Loaded from https://deno.land/std@0.78.0/encoding/_yaml/mark.ts
|
||||
|
||||
|
||||
// Ported from js-yaml v3.13.1:
|
||||
// https://github.com/nodeca/js-yaml/commit/665aadda42349dcae869f12040d9b10ef18d12da
|
||||
// Copyright 2011-2015 by Vitaly Puzrin. All rights reserved. MIT license.
|
||||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
import { repeat } from "./utils.ts";
|
||||
|
||||
export class Mark {
|
||||
constructor(
|
||||
public name: string,
|
||||
public buffer: string,
|
||||
public position: number,
|
||||
public line: number,
|
||||
public column: number,
|
||||
) {}
|
||||
|
||||
public getSnippet(indent = 4, maxLength = 75): string | null {
|
||||
if (!this.buffer) return null;
|
||||
|
||||
let head = "";
|
||||
let start = this.position;
|
||||
|
||||
while (
|
||||
start > 0 &&
|
||||
"\x00\r\n\x85\u2028\u2029".indexOf(this.buffer.charAt(start - 1)) === -1
|
||||
) {
|
||||
start -= 1;
|
||||
if (this.position - start > maxLength / 2 - 1) {
|
||||
head = " ... ";
|
||||
start += 5;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let tail = "";
|
||||
let end = this.position;
|
||||
|
||||
while (
|
||||
end < this.buffer.length &&
|
||||
"\x00\r\n\x85\u2028\u2029".indexOf(this.buffer.charAt(end)) === -1
|
||||
) {
|
||||
end += 1;
|
||||
if (end - this.position > maxLength / 2 - 1) {
|
||||
tail = " ... ";
|
||||
end -= 5;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const snippet = this.buffer.slice(start, end);
|
||||
return `${repeat(" ", indent)}${head}${snippet}${tail}\n${
|
||||
repeat(
|
||||
" ",
|
||||
indent + this.position - start + head.length,
|
||||
)
|
||||
}^`;
|
||||
}
|
||||
|
||||
public toString(compact?: boolean): string {
|
||||
let snippet,
|
||||
where = "";
|
||||
|
||||
if (this.name) {
|
||||
where += `in "${this.name}" `;
|
||||
}
|
||||
|
||||
where += `at line ${this.line + 1}, column ${this.column + 1}`;
|
||||
|
||||
if (!compact) {
|
||||
snippet = this.getSnippet();
|
||||
|
||||
if (snippet) {
|
||||
where += `:\n${snippet}`;
|
||||
}
|
||||
}
|
||||
|
||||
return where;
|
||||
}
|
||||
}
|
@ -0,0 +1,390 @@
|
||||
// Loaded from https://deno.land/std@0.80.0/path/glob.ts
|
||||
|
||||
|
||||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
// This module is browser compatible.
|
||||
|
||||
import { osType } from "../_util/os.ts";
|
||||
import { join, normalize } from "./mod.ts";
|
||||
import { SEP, SEP_PATTERN } from "./separator.ts";
|
||||
|
||||
export interface GlobOptions {
|
||||
/** Extended glob syntax.
|
||||
* See https://www.linuxjournal.com/content/bash-extended-globbing. Defaults
|
||||
* to true. */
|
||||
extended?: boolean;
|
||||
/** Globstar syntax.
|
||||
* See https://www.linuxjournal.com/content/globstar-new-bash-globbing-option.
|
||||
* If false, `**` is treated like `*`. Defaults to true. */
|
||||
globstar?: boolean;
|
||||
/** Operating system. Defaults to the native OS. */
|
||||
os?: typeof Deno.build.os;
|
||||
}
|
||||
|
||||
export type GlobToRegExpOptions = GlobOptions;
|
||||
|
||||
// deno-fmt-ignore
|
||||
const regExpEscapeChars = ["!", "$", "(", ")", "*", "+", ".", "=", "?", "[", "\\", "^", "{", "|"];
|
||||
const rangeEscapeChars = ["-", "\\", "]"];
|
||||
|
||||
/** Convert a glob string to a regular expression.
|
||||
*
|
||||
* Tries to match bash glob expansion as closely as possible.
|
||||
*
|
||||
* Basic glob syntax:
|
||||
* - `*` - Matches everything without leaving the path segment.
|
||||
* - `{foo,bar}` - Matches `foo` or `bar`.
|
||||
* - `[abcd]` - Matches `a`, `b`, `c` or `d`.
|
||||
* - `[a-d]` - Matches `a`, `b`, `c` or `d`.
|
||||
* - `[!abcd]` - Matches any single character besides `a`, `b`, `c` or `d`.
|
||||
* - `[[:<class>:]]` - Matches any character belonging to `<class>`.
|
||||
* - `[[:alnum:]]` - Matches any digit or letter.
|
||||
* - `[[:digit:]abc]` - Matches any digit, `a`, `b` or `c`.
|
||||
* - See https://facelessuser.github.io/wcmatch/glob/#posix-character-classes
|
||||
* for a complete list of supported character classes.
|
||||
* - `\` - Escapes the next character for an `os` other than `"windows"`.
|
||||
* - \` - Escapes the next character for `os` set to `"windows"`.
|
||||
* - `/` - Path separator.
|
||||
* - `\` - Additional path separator only for `os` set to `"windows"`.
|
||||
*
|
||||
* Extended syntax:
|
||||
* - Requires `{ extended: true }`.
|
||||
* - `?(foo|bar)` - Matches 0 or 1 instance of `{foo,bar}`.
|
||||
* - `@(foo|bar)` - Matches 1 instance of `{foo,bar}`. They behave the same.
|
||||
* - `*(foo|bar)` - Matches _n_ instances of `{foo,bar}`.
|
||||
* - `+(foo|bar)` - Matches _n > 0_ instances of `{foo,bar}`.
|
||||
* - `!(foo|bar)` - Matches anything other than `{foo,bar}`.
|
||||
* - See https://www.linuxjournal.com/content/bash-extended-globbing.
|
||||
*
|
||||
* Globstar syntax:
|
||||
* - Requires `{ globstar: true }`.
|
||||
* - `**` - Matches any number of any path segments.
|
||||
* - Must comprise its entire path segment in the provided glob.
|
||||
* - See https://www.linuxjournal.com/content/globstar-new-bash-globbing-option.
|
||||
*
|
||||
* Note the following properties:
|
||||
* - The generated `RegExp` is anchored at both start and end.
|
||||
* - Repeating and trailing separators are tolerated. Trailing separators in the
|
||||
* provided glob have no meaning and are discarded.
|
||||
* - Absolute globs will only match absolute paths, etc.
|
||||
* - Empty globs will match nothing.
|
||||
* - Any special glob syntax must be contained to one path segment. For example,
|
||||
* `?(foo|bar/baz)` is invalid. The separator will take precendence and the
|
||||
* first segment ends with an unclosed group.
|
||||
* - If a path segment ends with unclosed groups or a dangling escape prefix, a
|
||||
* parse error has occured. Every character for that segment is taken
|
||||
* literally in this event.
|
||||
*
|
||||
* Limitations:
|
||||
* - A negative group like `!(foo|bar)` will wrongly be converted to a negative
|
||||
* look-ahead followed by a wildcard. This means that `!(foo).js` will wrongly
|
||||
* fail to match `foobar.js`, even though `foobar` is not `foo`. Effectively,
|
||||
* `!(foo|bar)` is treated like `!(@(foo|bar)*)`. This will work correctly if
|
||||
* the group occurs not nested at the end of the segment. */
|
||||
export function globToRegExp(
|
||||
glob: string,
|
||||
{ extended = true, globstar: globstarOption = true, os = osType }:
|
||||
GlobToRegExpOptions = {},
|
||||
): RegExp {
|
||||
if (glob == "") {
|
||||
return /(?!)/;
|
||||
}
|
||||
|
||||
const sep = os == "windows" ? "(?:\\\\|/)+" : "/+";
|
||||
const sepMaybe = os == "windows" ? "(?:\\\\|/)*" : "/*";
|
||||
const seps = os == "windows" ? ["\\", "/"] : ["/"];
|
||||
const globstar = os == "windows"
|
||||
? "(?:[^\\\\/]*(?:\\\\|/|$)+)*"
|
||||
: "(?:[^/]*(?:/|$)+)*";
|
||||
const wildcard = os == "windows" ? "[^\\\\/]*" : "[^/]*";
|
||||
const escapePrefix = os == "windows" ? "`" : "\\";
|
||||
|
||||
// Remove trailing separators.
|
||||
let newLength = glob.length;
|
||||
for (; newLength > 1 && seps.includes(glob[newLength - 1]); newLength--);
|
||||
glob = glob.slice(0, newLength);
|
||||
|
||||
let regExpString = "";
|
||||
|
||||
// Terminates correctly. Trust that `j` is incremented every iteration.
|
||||
for (let j = 0; j < glob.length;) {
|
||||
let segment = "";
|
||||
const groupStack = [];
|
||||
let inRange = false;
|
||||
let inEscape = false;
|
||||
let endsWithSep = false;
|
||||
let i = j;
|
||||
|
||||
// Terminates with `i` at the non-inclusive end of the current segment.
|
||||
for (; i < glob.length && !seps.includes(glob[i]); i++) {
|
||||
if (inEscape) {
|
||||
inEscape = false;
|
||||
const escapeChars = inRange ? rangeEscapeChars : regExpEscapeChars;
|
||||
segment += escapeChars.includes(glob[i]) ? `\\${glob[i]}` : glob[i];
|
||||
continue;
|
||||
}
|
||||
|
||||
if (glob[i] == escapePrefix) {
|
||||
inEscape = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (glob[i] == "[") {
|
||||
if (!inRange) {
|
||||
inRange = true;
|
||||
segment += "[";
|
||||
if (glob[i + 1] == "!") {
|
||||
i++;
|
||||
segment += "^";
|
||||
} else if (glob[i + 1] == "^") {
|
||||
i++;
|
||||
segment += "\\^";
|
||||
}
|
||||
continue;
|
||||
} else if (glob[i + 1] == ":") {
|
||||
let k = i + 1;
|
||||
let value = "";
|
||||
while (glob[k + 1] != null && glob[k + 1] != ":") {
|
||||
value += glob[k + 1];
|
||||
k++;
|
||||
}
|
||||
if (glob[k + 1] == ":" && glob[k + 2] == "]") {
|
||||
i = k + 2;
|
||||
if (value == "alnum") segment += "\\dA-Za-z";
|
||||
else if (value == "alpha") segment += "A-Za-z";
|
||||
else if (value == "ascii") segment += "\x00-\x7F";
|
||||
else if (value == "blank") segment += "\t ";
|
||||
else if (value == "cntrl") segment += "\x00-\x1F\x7F";
|
||||
else if (value == "digit") segment += "\\d";
|
||||
else if (value == "graph") segment += "\x21-\x7E";
|
||||
else if (value == "lower") segment += "a-z";
|
||||
else if (value == "print") segment += "\x20-\x7E";
|
||||
else if (value == "punct") {
|
||||
segment += "!\"#$%&'()*+,\\-./:;<=>?@[\\\\\\]^_‘{|}~";
|
||||
} else if (value == "space") segment += "\\s\v";
|
||||
else if (value == "upper") segment += "A-Z";
|
||||
else if (value == "word") segment += "\\w";
|
||||
else if (value == "xdigit") segment += "\\dA-Fa-f";
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (glob[i] == "]" && inRange) {
|
||||
inRange = false;
|
||||
segment += "]";
|
||||
continue;
|
||||
}
|
||||
|
||||
if (inRange) {
|
||||
if (glob[i] == "\\") {
|
||||
segment += `\\\\`;
|
||||
} else {
|
||||
segment += glob[i];
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (
|
||||
glob[i] == ")" && groupStack.length > 0 &&
|
||||
groupStack[groupStack.length - 1] != "BRACE"
|
||||
) {
|
||||
segment += ")";
|
||||
const type = groupStack.pop()!;
|
||||
if (type == "!") {
|
||||
segment += wildcard;
|
||||
} else if (type != "@") {
|
||||
segment += type;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (
|
||||
glob[i] == "|" && groupStack.length > 0 &&
|
||||
groupStack[groupStack.length - 1] != "BRACE"
|
||||
) {
|
||||
segment += "|";
|
||||
continue;
|
||||
}
|
||||
|
||||
if (glob[i] == "+" && extended && glob[i + 1] == "(") {
|
||||
i++;
|
||||
groupStack.push("+");
|
||||
segment += "(?:";
|
||||
continue;
|
||||
}
|
||||
|
||||
if (glob[i] == "@" && extended && glob[i + 1] == "(") {
|
||||
i++;
|
||||
groupStack.push("@");
|
||||
segment += "(?:";
|
||||
continue;
|
||||
}
|
||||
|
||||
if (glob[i] == "?") {
|
||||
if (extended && glob[i + 1] == "(") {
|
||||
i++;
|
||||
groupStack.push("?");
|
||||
segment += "(?:";
|
||||
} else {
|
||||
segment += ".";
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (glob[i] == "!" && extended && glob[i + 1] == "(") {
|
||||
i++;
|
||||
groupStack.push("!");
|
||||
segment += "(?!";
|
||||
continue;
|
||||
}
|
||||
|
||||
if (glob[i] == "{") {
|
||||
groupStack.push("BRACE");
|
||||
segment += "(?:";
|
||||
continue;
|
||||
}
|
||||
|
||||
if (glob[i] == "}" && groupStack[groupStack.length - 1] == "BRACE") {
|
||||
groupStack.pop();
|
||||
segment += ")";
|
||||
continue;
|
||||
}
|
||||
|
||||
if (glob[i] == "," && groupStack[groupStack.length - 1] == "BRACE") {
|
||||
segment += "|";
|
||||
continue;
|
||||
}
|
||||
|
||||
if (glob[i] == "*") {
|
||||
if (extended && glob[i + 1] == "(") {
|
||||
i++;
|
||||
groupStack.push("*");
|
||||
segment += "(?:";
|
||||
} else {
|
||||
const prevChar = glob[i - 1];
|
||||
let numStars = 1;
|
||||
while (glob[i + 1] == "*") {
|
||||
i++;
|
||||
numStars++;
|
||||
}
|
||||
const nextChar = glob[i + 1];
|
||||
if (
|
||||
globstarOption && numStars == 2 &&
|
||||
[...seps, undefined].includes(prevChar) &&
|
||||
[...seps, undefined].includes(nextChar)
|
||||
) {
|
||||
segment += globstar;
|
||||
endsWithSep = true;
|
||||
} else {
|
||||
segment += wildcard;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
segment += regExpEscapeChars.includes(glob[i]) ? `\\${glob[i]}` : glob[i];
|
||||
}
|
||||
|
||||
// Check for unclosed groups or a dangling backslash.
|
||||
if (groupStack.length > 0 || inRange || inEscape) {
|
||||
// Parse failure. Take all characters from this segment literally.
|
||||
segment = "";
|
||||
for (const c of glob.slice(j, i)) {
|
||||
segment += regExpEscapeChars.includes(c) ? `\\${c}` : c;
|
||||
endsWithSep = false;
|
||||
}
|
||||
}
|
||||
|
||||
regExpString += segment;
|
||||
if (!endsWithSep) {
|
||||
regExpString += i < glob.length ? sep : sepMaybe;
|
||||
endsWithSep = true;
|
||||
}
|
||||
|
||||
// Terminates with `i` at the start of the next segment.
|
||||
while (seps.includes(glob[i])) i++;
|
||||
|
||||
// Check that the next value of `j` is indeed higher than the current value.
|
||||
if (!(i > j)) {
|
||||
throw new Error("Assertion failure: i > j (potential infinite loop)");
|
||||
}
|
||||
j = i;
|
||||
}
|
||||
|
||||
regExpString = `^${regExpString}$`;
|
||||
return new RegExp(regExpString);
|
||||
}
|
||||
|
||||
/** Test whether the given string is a glob */
|
||||
export function isGlob(str: string): boolean {
|
||||
const chars: Record<string, string> = { "{": "}", "(": ")", "[": "]" };
|
||||
const regex =
|
||||
/\\(.)|(^!|\*|[\].+)]\?|\[[^\\\]]+\]|\{[^\\}]+\}|\(\?[:!=][^\\)]+\)|\([^|]+\|[^\\)]+\))/;
|
||||
|
||||
if (str === "") {
|
||||
return false;
|
||||
}
|
||||
|
||||
let match: RegExpExecArray | null;
|
||||
|
||||
while ((match = regex.exec(str))) {
|
||||
if (match[2]) return true;
|
||||
let idx = match.index + match[0].length;
|
||||
|
||||
// if an open bracket/brace/paren is escaped,
|
||||
// set the index to the next closing character
|
||||
const open = match[1];
|
||||
const close = open ? chars[open] : null;
|
||||
if (open && close) {
|
||||
const n = str.indexOf(close, idx);
|
||||
if (n !== -1) {
|
||||
idx = n + 1;
|
||||
}
|
||||
}
|
||||
|
||||
str = str.slice(idx);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Like normalize(), but doesn't collapse "**\/.." when `globstar` is true. */
|
||||
export function normalizeGlob(
|
||||
glob: string,
|
||||
{ globstar = false }: GlobOptions = {},
|
||||
): string {
|
||||
if (glob.match(/\0/g)) {
|
||||
throw new Error(`Glob contains invalid characters: "${glob}"`);
|
||||
}
|
||||
if (!globstar) {
|
||||
return normalize(glob);
|
||||
}
|
||||
const s = SEP_PATTERN.source;
|
||||
const badParentPattern = new RegExp(
|
||||
`(?<=(${s}|^)\\*\\*${s})\\.\\.(?=${s}|$)`,
|
||||
"g",
|
||||
);
|
||||
return normalize(glob.replace(badParentPattern, "\0")).replace(/\0/g, "..");
|
||||
}
|
||||
|
||||
/** Like join(), but doesn't collapse "**\/.." when `globstar` is true. */
|
||||
export function joinGlobs(
|
||||
globs: string[],
|
||||
{ extended = false, globstar = false }: GlobOptions = {},
|
||||
): string {
|
||||
if (!globstar || globs.length == 0) {
|
||||
return join(...globs);
|
||||
}
|
||||
if (globs.length === 0) return ".";
|
||||
let joined: string | undefined;
|
||||
for (const glob of globs) {
|
||||
const path = glob;
|
||||
if (path.length > 0) {
|
||||
if (!joined) joined = path;
|
||||
else joined += `${SEP}${path}`;
|
||||
}
|
||||
}
|
||||
if (!joined) return ".";
|
||||
return normalizeGlob(joined, { extended, globstar });
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
// Loaded from https://deno.land/x/ramda@v0.27.2/source/equals.js
|
||||
|
||||
|
||||
import _curry2 from './internal/_curry2.js';
|
||||
import _equals from './internal/_equals.js';
|
||||
|
||||
|
||||
/**
|
||||
* Returns `true` if its arguments are equivalent, `false` otherwise. Handles
|
||||
* cyclical data structures.
|
||||
*
|
||||
* Dispatches symmetrically to the `equals` methods of both arguments, if
|
||||
* present.
|
||||
*
|
||||
* @func
|
||||
* @memberOf R
|
||||
* @since v0.15.0
|
||||
* @category Relation
|
||||
* @sig a -> b -> Boolean
|
||||
* @param {*} a
|
||||
* @param {*} b
|
||||
* @return {Boolean}
|
||||
* @example
|
||||
*
|
||||
* R.equals(1, 1); //=> true
|
||||
* R.equals(1, '1'); //=> false
|
||||
* R.equals([1, 2, 3], [1, 2, 3]); //=> true
|
||||
*
|
||||
* const a = {}; a.v = a;
|
||||
* const b = {}; b.v = b;
|
||||
* R.equals(a, b); //=> true
|
||||
*/
|
||||
var equals = _curry2(function equals(a, b) {
|
||||
return _equals(a, b, [], []);
|
||||
});
|
||||
export default equals;
|
@ -0,0 +1,21 @@
|
||||
// Loaded from https://deno.land/x/segno@v1.1.0/lib/validations/isUUID.ts
|
||||
|
||||
|
||||
// @ts-ignore allowing typedoc to build
|
||||
import { assertString } from '../helpers/assertString.ts';
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
const uuid = {
|
||||
3: /^[0-9A-F]{8}-[0-9A-F]{4}-3[0-9A-F]{3}-[0-9A-F]{4}-[0-9A-F]{12}$/i,
|
||||
4: /^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i,
|
||||
5: /^[0-9A-F]{8}-[0-9A-F]{4}-5[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i,
|
||||
all: /^[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}$/i,
|
||||
};
|
||||
|
||||
export const isUUID = (str: string, version: 3 | 4 | 5 | 'all' = 'all') => {
|
||||
assertString(str);
|
||||
const pattern = (uuid as any)[version];
|
||||
return pattern && pattern.test(str);
|
||||
};
|
@ -0,0 +1,512 @@
|
||||
// Loaded from https://deno.land/x/deno_image@v0.0.3/lib/decoders/fast-png/iobuffer/IOBuffer.ts
|
||||
|
||||
|
||||
import { decode, encode } from './utf8.ts';
|
||||
|
||||
const defaultByteLength = 1024 * 8;
|
||||
|
||||
type InputData = number | ArrayBufferLike | ArrayBufferView | IOBuffer;
|
||||
|
||||
interface IOBufferOptions {
|
||||
/**
|
||||
* Ignore the first n bytes of the ArrayBuffer.
|
||||
*/
|
||||
offset?: number;
|
||||
}
|
||||
|
||||
export class IOBuffer {
|
||||
/**
|
||||
* Reference to the internal ArrayBuffer object.
|
||||
*/
|
||||
public buffer: ArrayBufferLike;
|
||||
|
||||
/**
|
||||
* Byte length of the internal ArrayBuffer.
|
||||
*/
|
||||
public byteLength: number;
|
||||
|
||||
/**
|
||||
* Byte offset of the internal ArrayBuffer.
|
||||
*/
|
||||
public byteOffset: number;
|
||||
|
||||
/**
|
||||
* Byte length of the internal ArrayBuffer.
|
||||
*/
|
||||
public length: number;
|
||||
|
||||
/**
|
||||
* The current offset of the buffer's pointer.
|
||||
*/
|
||||
public offset: number;
|
||||
|
||||
private lastWrittenByte: number;
|
||||
private littleEndian: boolean;
|
||||
|
||||
private _data: DataView;
|
||||
private _mark: number;
|
||||
private _marks: number[];
|
||||
|
||||
/**
|
||||
* @param data - The data to construct the IOBuffer with.
|
||||
* If data is a number, it will be the new buffer's length<br>
|
||||
* If data is `undefined`, the buffer will be initialized with a default length of 8Kb<br>
|
||||
* If data is an ArrayBuffer, SharedArrayBuffer, an ArrayBufferView (Typed Array) or an IOBuffer instance
|
||||
* a view will be created over the underlying ArrayBuffer.
|
||||
* @param options
|
||||
*/
|
||||
public constructor(
|
||||
data: InputData = defaultByteLength,
|
||||
options: IOBufferOptions = {},
|
||||
) {
|
||||
let dataIsGiven = false;
|
||||
if (typeof data === 'number') {
|
||||
data = new ArrayBuffer(data);
|
||||
} else {
|
||||
dataIsGiven = true;
|
||||
this.lastWrittenByte = data.byteLength;
|
||||
}
|
||||
|
||||
const offset = options.offset ? options.offset >>> 0 : 0;
|
||||
const byteLength = data.byteLength - offset;
|
||||
let dvOffset = offset;
|
||||
if (ArrayBuffer.isView(data) || data instanceof IOBuffer) {
|
||||
if (data.byteLength !== data.buffer.byteLength) {
|
||||
dvOffset = data.byteOffset + offset;
|
||||
}
|
||||
data = data.buffer;
|
||||
}
|
||||
if (dataIsGiven) {
|
||||
this.lastWrittenByte = byteLength;
|
||||
} else {
|
||||
this.lastWrittenByte = 0;
|
||||
}
|
||||
this.buffer = data;
|
||||
this.length = byteLength;
|
||||
this.byteLength = byteLength;
|
||||
this.byteOffset = dvOffset;
|
||||
this.offset = 0;
|
||||
this.littleEndian = true;
|
||||
this._data = new DataView(this.buffer, dvOffset, byteLength);
|
||||
this._mark = 0;
|
||||
this._marks = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the memory allocated to the buffer is sufficient to store more
|
||||
* bytes after the offset.
|
||||
* @param byteLength - The needed memory in bytes.
|
||||
* @returns `true` if there is sufficient space and `false` otherwise.
|
||||
*/
|
||||
public available(byteLength = 1): boolean {
|
||||
return this.offset + byteLength <= this.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if little-endian mode is used for reading and writing multi-byte
|
||||
* values.
|
||||
* @returns `true` if little-endian mode is used, `false` otherwise.
|
||||
*/
|
||||
public isLittleEndian(): boolean {
|
||||
return this.littleEndian;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set little-endian mode for reading and writing multi-byte values.
|
||||
*/
|
||||
public setLittleEndian(): this {
|
||||
this.littleEndian = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if big-endian mode is used for reading and writing multi-byte values.
|
||||
* @returns `true` if big-endian mode is used, `false` otherwise.
|
||||
*/
|
||||
public isBigEndian(): boolean {
|
||||
return !this.littleEndian;
|
||||
}
|
||||
|
||||
/**
|
||||
* Switches to big-endian mode for reading and writing multi-byte values.
|
||||
*/
|
||||
public setBigEndian(): this {
|
||||
this.littleEndian = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Move the pointer n bytes forward.
|
||||
* @param n - Number of bytes to skip.
|
||||
*/
|
||||
public skip(n = 1): this {
|
||||
this.offset += n;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Move the pointer to the given offset.
|
||||
* @param offset
|
||||
*/
|
||||
public seek(offset: number): this {
|
||||
this.offset = offset;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the current pointer offset.
|
||||
* @see {@link IOBuffer#reset}
|
||||
*/
|
||||
public mark(): this {
|
||||
this._mark = this.offset;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Move the pointer back to the last pointer offset set by mark.
|
||||
* @see {@link IOBuffer#mark}
|
||||
*/
|
||||
public reset(): this {
|
||||
this.offset = this._mark;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Push the current pointer offset to the mark stack.
|
||||
* @see {@link IOBuffer#popMark}
|
||||
*/
|
||||
public pushMark(): this {
|
||||
this._marks.push(this.offset);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pop the last pointer offset from the mark stack, and set the current
|
||||
* pointer offset to the popped value.
|
||||
* @see {@link IOBuffer#pushMark}
|
||||
*/
|
||||
public popMark(): this {
|
||||
const offset = this._marks.pop();
|
||||
if (offset === undefined) {
|
||||
throw new Error('Mark stack empty');
|
||||
}
|
||||
this.seek(offset);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Move the pointer offset back to 0.
|
||||
*/
|
||||
public rewind(): this {
|
||||
this.offset = 0;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure the buffer has sufficient memory to write a given byteLength at
|
||||
* the current pointer offset.
|
||||
* If the buffer's memory is insufficient, this method will create a new
|
||||
* buffer (a copy) with a length that is twice (byteLength + current offset).
|
||||
* @param byteLength
|
||||
*/
|
||||
public ensureAvailable(byteLength = 1): this {
|
||||
if (!this.available(byteLength)) {
|
||||
const lengthNeeded = this.offset + byteLength;
|
||||
const newLength = lengthNeeded * 2;
|
||||
const newArray = new Uint8Array(newLength);
|
||||
newArray.set(new Uint8Array(this.buffer));
|
||||
this.buffer = newArray.buffer;
|
||||
this.length = this.byteLength = newLength;
|
||||
this._data = new DataView(this.buffer);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a byte and return false if the byte's value is 0, or true otherwise.
|
||||
* Moves pointer forward by one byte.
|
||||
*/
|
||||
public readBoolean(): boolean {
|
||||
return this.readUint8() !== 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a signed 8-bit integer and move pointer forward by 1 byte.
|
||||
*/
|
||||
public readInt8(): number {
|
||||
return this._data.getInt8(this.offset++);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read an unsigned 8-bit integer and move pointer forward by 1 byte.
|
||||
*/
|
||||
public readUint8(): number {
|
||||
return this._data.getUint8(this.offset++);
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias for {@link IOBuffer#readUint8}.
|
||||
*/
|
||||
public readByte(): number {
|
||||
return this.readUint8();
|
||||
}
|
||||
|
||||
/**
|
||||
* Read `n` bytes and move pointer forward by `n` bytes.
|
||||
*/
|
||||
public readBytes(n = 1): Uint8Array {
|
||||
const bytes = new Uint8Array(n);
|
||||
for (let i = 0; i < n; i++) {
|
||||
bytes[i] = this.readByte();
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a 16-bit signed integer and move pointer forward by 2 bytes.
|
||||
*/
|
||||
public readInt16(): number {
|
||||
const value = this._data.getInt16(this.offset, this.littleEndian);
|
||||
this.offset += 2;
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a 16-bit unsigned integer and move pointer forward by 2 bytes.
|
||||
*/
|
||||
public readUint16(): number {
|
||||
const value = this._data.getUint16(this.offset, this.littleEndian);
|
||||
this.offset += 2;
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a 32-bit signed integer and move pointer forward by 4 bytes.
|
||||
*/
|
||||
public readInt32(): number {
|
||||
const value = this._data.getInt32(this.offset, this.littleEndian);
|
||||
this.offset += 4;
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a 32-bit unsigned integer and move pointer forward by 4 bytes.
|
||||
*/
|
||||
public readUint32(): number {
|
||||
const value = this._data.getUint32(this.offset, this.littleEndian);
|
||||
this.offset += 4;
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a 32-bit floating number and move pointer forward by 4 bytes.
|
||||
*/
|
||||
public readFloat32(): number {
|
||||
const value = this._data.getFloat32(this.offset, this.littleEndian);
|
||||
this.offset += 4;
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a 64-bit floating number and move pointer forward by 8 bytes.
|
||||
*/
|
||||
public readFloat64(): number {
|
||||
const value = this._data.getFloat64(this.offset, this.littleEndian);
|
||||
this.offset += 8;
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a 1-byte ASCII character and move pointer forward by 1 byte.
|
||||
*/
|
||||
public readChar(): string {
|
||||
return String.fromCharCode(this.readInt8());
|
||||
}
|
||||
|
||||
/**
|
||||
* Read `n` 1-byte ASCII characters and move pointer forward by `n` bytes.
|
||||
*/
|
||||
public readChars(n = 1): string {
|
||||
let result = '';
|
||||
for (let i = 0; i < n; i++) {
|
||||
result += this.readChar();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the next `n` bytes, return a UTF-8 decoded string and move pointer
|
||||
* forward by `n` bytes.
|
||||
*/
|
||||
public readUtf8(n = 1): string {
|
||||
return decode(this.readBytes(n));
|
||||
}
|
||||
|
||||
/**
|
||||
* Write 0xff if the passed value is truthy, 0x00 otherwise and move pointer
|
||||
* forward by 1 byte.
|
||||
*/
|
||||
public writeBoolean(value: unknown): this {
|
||||
this.writeUint8(value ? 0xff : 0x00);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write `value` as an 8-bit signed integer and move pointer forward by 1 byte.
|
||||
*/
|
||||
public writeInt8(value: number): this {
|
||||
this.ensureAvailable(1);
|
||||
this._data.setInt8(this.offset++, value);
|
||||
this._updateLastWrittenByte();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write `value` as an 8-bit unsigned integer and move pointer forward by 1
|
||||
* byte.
|
||||
*/
|
||||
public writeUint8(value: number): this {
|
||||
this.ensureAvailable(1);
|
||||
this._data.setUint8(this.offset++, value);
|
||||
this._updateLastWrittenByte();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* An alias for {@link IOBuffer#writeUint8}.
|
||||
*/
|
||||
public writeByte(value: number): this {
|
||||
return this.writeUint8(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write all elements of `bytes` as uint8 values and move pointer forward by
|
||||
* `bytes.length` bytes.
|
||||
*/
|
||||
public writeBytes(bytes: ArrayLike<number>): this {
|
||||
this.ensureAvailable(bytes.length);
|
||||
for (let i = 0; i < bytes.length; i++) {
|
||||
this._data.setUint8(this.offset++, bytes[i]);
|
||||
}
|
||||
this._updateLastWrittenByte();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write `value` as a 16-bit signed integer and move pointer forward by 2
|
||||
* bytes.
|
||||
*/
|
||||
public writeInt16(value: number): this {
|
||||
this.ensureAvailable(2);
|
||||
this._data.setInt16(this.offset, value, this.littleEndian);
|
||||
this.offset += 2;
|
||||
this._updateLastWrittenByte();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write `value` as a 16-bit unsigned integer and move pointer forward by 2
|
||||
* bytes.
|
||||
*/
|
||||
public writeUint16(value: number): this {
|
||||
this.ensureAvailable(2);
|
||||
this._data.setUint16(this.offset, value, this.littleEndian);
|
||||
this.offset += 2;
|
||||
this._updateLastWrittenByte();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write `value` as a 32-bit signed integer and move pointer forward by 4
|
||||
* bytes.
|
||||
*/
|
||||
public writeInt32(value: number): this {
|
||||
this.ensureAvailable(4);
|
||||
this._data.setInt32(this.offset, value, this.littleEndian);
|
||||
this.offset += 4;
|
||||
this._updateLastWrittenByte();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write `value` as a 32-bit unsigned integer and move pointer forward by 4
|
||||
* bytes.
|
||||
*/
|
||||
public writeUint32(value: number): this {
|
||||
this.ensureAvailable(4);
|
||||
this._data.setUint32(this.offset, value, this.littleEndian);
|
||||
this.offset += 4;
|
||||
this._updateLastWrittenByte();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write `value` as a 32-bit floating number and move pointer forward by 4
|
||||
* bytes.
|
||||
*/
|
||||
public writeFloat32(value: number): this {
|
||||
this.ensureAvailable(4);
|
||||
this._data.setFloat32(this.offset, value, this.littleEndian);
|
||||
this.offset += 4;
|
||||
this._updateLastWrittenByte();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write `value` as a 64-bit floating number and move pointer forward by 8
|
||||
* bytes.
|
||||
*/
|
||||
public writeFloat64(value: number): this {
|
||||
this.ensureAvailable(8);
|
||||
this._data.setFloat64(this.offset, value, this.littleEndian);
|
||||
this.offset += 8;
|
||||
this._updateLastWrittenByte();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the charCode of `str`'s first character as an 8-bit unsigned integer
|
||||
* and move pointer forward by 1 byte.
|
||||
*/
|
||||
public writeChar(str: string): this {
|
||||
return this.writeUint8(str.charCodeAt(0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the charCodes of all `str`'s characters as 8-bit unsigned integers
|
||||
* and move pointer forward by `str.length` bytes.
|
||||
*/
|
||||
public writeChars(str: string): this {
|
||||
for (let i = 0; i < str.length; i++) {
|
||||
this.writeUint8(str.charCodeAt(i));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* UTF-8 encode and write `str` to the current pointer offset and move pointer
|
||||
* forward according to the encoded length.
|
||||
*/
|
||||
public writeUtf8(str: string): this {
|
||||
return this.writeBytes(encode(str));
|
||||
}
|
||||
|
||||
/**
|
||||
* Export a Uint8Array view of the internal buffer.
|
||||
* The view starts at the byte offset and its length
|
||||
* is calculated to stop at the last written byte or the original length.
|
||||
*/
|
||||
public toArray(): Uint8Array {
|
||||
return new Uint8Array(this.buffer, this.byteOffset, this.lastWrittenByte);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the last written byte offset
|
||||
* @private
|
||||
*/
|
||||
private _updateLastWrittenByte(): void {
|
||||
if (this.offset > this.lastWrittenByte) {
|
||||
this.lastWrittenByte = this.offset;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,128 @@
|
||||
// Loaded from https://deno.land/x/mysql/src/packets/parsers/result.ts
|
||||
|
||||
|
||||
import type { BufferReader } from "../../buffer.ts";
|
||||
import {
|
||||
MYSQL_TYPE_DATE,
|
||||
MYSQL_TYPE_DATETIME,
|
||||
MYSQL_TYPE_DATETIME2,
|
||||
MYSQL_TYPE_DECIMAL,
|
||||
MYSQL_TYPE_DOUBLE,
|
||||
MYSQL_TYPE_FLOAT,
|
||||
MYSQL_TYPE_INT24,
|
||||
MYSQL_TYPE_LONG,
|
||||
MYSQL_TYPE_LONGLONG,
|
||||
MYSQL_TYPE_NEWDATE,
|
||||
MYSQL_TYPE_NEWDECIMAL,
|
||||
MYSQL_TYPE_SHORT,
|
||||
MYSQL_TYPE_STRING,
|
||||
MYSQL_TYPE_TIME,
|
||||
MYSQL_TYPE_TIME2,
|
||||
MYSQL_TYPE_TIMESTAMP,
|
||||
MYSQL_TYPE_TIMESTAMP2,
|
||||
MYSQL_TYPE_TINY,
|
||||
MYSQL_TYPE_VAR_STRING,
|
||||
MYSQL_TYPE_VARCHAR,
|
||||
} from "../../constant/mysql_types.ts";
|
||||
|
||||
/** @ignore */
|
||||
export interface FieldInfo {
|
||||
catalog: string;
|
||||
schema: string;
|
||||
table: string;
|
||||
originTable: string;
|
||||
name: string;
|
||||
originName: string;
|
||||
encoding: number;
|
||||
fieldLen: number;
|
||||
fieldType: number;
|
||||
fieldFlag: number;
|
||||
decimals: number;
|
||||
defaultVal: string;
|
||||
}
|
||||
|
||||
/** @ignore */
|
||||
export function parseField(reader: BufferReader): FieldInfo {
|
||||
const catalog = reader.readLenCodeString()!;
|
||||
const schema = reader.readLenCodeString()!;
|
||||
const table = reader.readLenCodeString()!;
|
||||
const originTable = reader.readLenCodeString()!;
|
||||
const name = reader.readLenCodeString()!;
|
||||
const originName = reader.readLenCodeString()!;
|
||||
reader.skip(1);
|
||||
const encoding = reader.readUint16()!;
|
||||
const fieldLen = reader.readUint32()!;
|
||||
const fieldType = reader.readUint8()!;
|
||||
const fieldFlag = reader.readUint16()!;
|
||||
const decimals = reader.readUint8()!;
|
||||
reader.skip(1);
|
||||
const defaultVal = reader.readLenCodeString()!;
|
||||
return {
|
||||
catalog,
|
||||
schema,
|
||||
table,
|
||||
originName,
|
||||
fieldFlag,
|
||||
originTable,
|
||||
fieldLen,
|
||||
name,
|
||||
fieldType,
|
||||
encoding,
|
||||
decimals,
|
||||
defaultVal,
|
||||
};
|
||||
}
|
||||
|
||||
/** @ignore */
|
||||
export function parseRow(reader: BufferReader, fields: FieldInfo[]): any {
|
||||
const row: any = {};
|
||||
for (const field of fields) {
|
||||
const name = field.name;
|
||||
const val = reader.readLenCodeString();
|
||||
row[name] = val === null ? null : convertType(field, val);
|
||||
}
|
||||
return row;
|
||||
}
|
||||
|
||||
/** @ignore */
|
||||
function convertType(field: FieldInfo, val: string): any {
|
||||
const { fieldType, fieldLen } = field;
|
||||
switch (fieldType) {
|
||||
case MYSQL_TYPE_DECIMAL:
|
||||
case MYSQL_TYPE_DOUBLE:
|
||||
case MYSQL_TYPE_FLOAT:
|
||||
case MYSQL_TYPE_DATETIME2:
|
||||
return parseFloat(val);
|
||||
case MYSQL_TYPE_NEWDECIMAL:
|
||||
return val; // #42 MySQL's decimal type cannot be accurately represented by the Number.
|
||||
case MYSQL_TYPE_TINY:
|
||||
case MYSQL_TYPE_SHORT:
|
||||
case MYSQL_TYPE_LONG:
|
||||
case MYSQL_TYPE_INT24:
|
||||
return parseInt(val);
|
||||
case MYSQL_TYPE_LONGLONG:
|
||||
if (
|
||||
Number(val) < Number.MIN_SAFE_INTEGER ||
|
||||
Number(val) > Number.MAX_SAFE_INTEGER
|
||||
) {
|
||||
return BigInt(val);
|
||||
} else {
|
||||
return parseInt(val);
|
||||
}
|
||||
case MYSQL_TYPE_VARCHAR:
|
||||
case MYSQL_TYPE_VAR_STRING:
|
||||
case MYSQL_TYPE_STRING:
|
||||
case MYSQL_TYPE_TIME:
|
||||
case MYSQL_TYPE_TIME2:
|
||||
return val;
|
||||
case MYSQL_TYPE_DATE:
|
||||
case MYSQL_TYPE_TIMESTAMP:
|
||||
case MYSQL_TYPE_DATETIME:
|
||||
case MYSQL_TYPE_NEWDATE:
|
||||
case MYSQL_TYPE_TIMESTAMP2:
|
||||
case MYSQL_TYPE_DATETIME2:
|
||||
return new Date(val);
|
||||
default:
|
||||
return val;
|
||||
}
|
||||
}
|
@ -0,0 +1,175 @@
|
||||
// Loaded from https://deno.land/x/mongo@v0.20.0/src/collection/collection.ts
|
||||
|
||||
|
||||
import { Bson } from "../../deps.ts";
|
||||
import { WireProtocol } from "../protocol/mod.ts";
|
||||
import {
|
||||
CountOptions,
|
||||
DeleteOptions,
|
||||
DistinctOptions,
|
||||
Document,
|
||||
DropOptions,
|
||||
FindOptions,
|
||||
InsertOptions,
|
||||
UpdateOptions,
|
||||
} from "../types.ts";
|
||||
import { FindCursor } from "./commands/find.ts";
|
||||
import { AggregateCursor } from "./commands/aggregate.ts";
|
||||
import { update } from "./commands/update.ts";
|
||||
|
||||
export class Collection<T> {
|
||||
#protocol: WireProtocol;
|
||||
#dbName: string;
|
||||
|
||||
constructor(protocol: WireProtocol, dbName: string, readonly name: string) {
|
||||
this.#protocol = protocol;
|
||||
this.#dbName = dbName;
|
||||
}
|
||||
|
||||
find(filter?: Document, options?: FindOptions): FindCursor<T> {
|
||||
return new FindCursor<T>({
|
||||
filter,
|
||||
protocol: this.#protocol,
|
||||
collectionName: this.name,
|
||||
dbName: this.#dbName,
|
||||
options: options ?? {},
|
||||
});
|
||||
}
|
||||
|
||||
async findOne(
|
||||
filter?: Document,
|
||||
options?: FindOptions,
|
||||
): Promise<T | undefined> {
|
||||
const cursor = this.find(filter, options);
|
||||
return await cursor.next();
|
||||
}
|
||||
|
||||
async count(filter?: Document, options?: CountOptions): Promise<number> {
|
||||
const res = await this.#protocol.commandSingle(this.#dbName, {
|
||||
count: this.name,
|
||||
query: filter,
|
||||
...options,
|
||||
});
|
||||
const { n, ok } = res;
|
||||
if (ok === 1) {
|
||||
return n;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
async insertOne(doc: Document, options?: InsertOptions) {
|
||||
const { insertedIds } = await this.insertMany([doc], options);
|
||||
return insertedIds[0];
|
||||
}
|
||||
|
||||
async insert(docs: Document | Document[], options?: InsertOptions) {
|
||||
docs = Array.isArray(docs) ? docs : [docs];
|
||||
return this.insertMany(docs as Document[], options);
|
||||
}
|
||||
|
||||
async insertMany(
|
||||
docs: Document[],
|
||||
options?: InsertOptions,
|
||||
): Promise<{ insertedIds: Document[]; insertedCount: number }> {
|
||||
const insertedIds = docs.map((doc) => {
|
||||
if (!doc._id) {
|
||||
doc._id = new Bson.ObjectID();
|
||||
}
|
||||
return doc._id;
|
||||
});
|
||||
const res = await this.#protocol.commandSingle(this.#dbName, {
|
||||
insert: this.name,
|
||||
documents: docs,
|
||||
ordered: options?.ordered ?? true,
|
||||
writeConcern: options?.writeConcern,
|
||||
bypassDocumentValidation: options?.bypassDocumentValidation,
|
||||
comment: options?.comment,
|
||||
});
|
||||
const { writeErrors } = res;
|
||||
if (writeErrors) {
|
||||
const [{ errmsg }] = writeErrors;
|
||||
throw new Error(errmsg);
|
||||
}
|
||||
return {
|
||||
insertedIds,
|
||||
insertedCount: res.n,
|
||||
};
|
||||
}
|
||||
|
||||
async updateOne(filter: Document, update: Document, options?: UpdateOptions) {
|
||||
const {
|
||||
upsertedIds = [],
|
||||
upsertedCount,
|
||||
matchedCount,
|
||||
modifiedCount,
|
||||
} = await this.updateMany(filter, update, {
|
||||
...options,
|
||||
multi: false,
|
||||
});
|
||||
return {
|
||||
upsertedId: upsertedIds ? upsertedIds[0] : undefined,
|
||||
upsertedCount,
|
||||
matchedCount,
|
||||
modifiedCount,
|
||||
};
|
||||
}
|
||||
|
||||
async updateMany(filter: Document, doc: Document, options?: UpdateOptions) {
|
||||
return await update(this.#protocol, this.#dbName, this.name, filter, doc, {
|
||||
...options,
|
||||
multi: options?.multi ?? true,
|
||||
});
|
||||
}
|
||||
|
||||
async deleteMany(filter: Document, options?: DeleteOptions): Promise<number> {
|
||||
const res = await this.#protocol.commandSingle(this.#dbName, {
|
||||
delete: this.name,
|
||||
deletes: [
|
||||
{
|
||||
q: filter,
|
||||
limit: options?.limit ?? 0,
|
||||
collation: options?.collation,
|
||||
hint: options?.hint,
|
||||
comment: options?.comment,
|
||||
},
|
||||
],
|
||||
ordered: options?.ordered ?? true,
|
||||
writeConcern: options?.writeConcern,
|
||||
});
|
||||
return res.n;
|
||||
}
|
||||
|
||||
delete = this.deleteMany;
|
||||
|
||||
async deleteOne(filter: Document, options?: DeleteOptions) {
|
||||
return this.delete(filter, { ...options, limit: 1 });
|
||||
}
|
||||
|
||||
async drop(options?: DropOptions): Promise<void> {
|
||||
const res = await this.#protocol.commandSingle(this.#dbName, {
|
||||
drop: this.name,
|
||||
...options,
|
||||
});
|
||||
}
|
||||
|
||||
async distinct(key: string, query?: Document, options?: DistinctOptions) {
|
||||
const { values } = await this.#protocol.commandSingle(this.#dbName, {
|
||||
distinct: this.name,
|
||||
key,
|
||||
query,
|
||||
...options,
|
||||
});
|
||||
return values;
|
||||
}
|
||||
|
||||
aggregate(pipeline: Document[], options?: any): AggregateCursor<T> {
|
||||
return new AggregateCursor<T>({
|
||||
pipeline,
|
||||
protocol: this.#protocol,
|
||||
dbName: this.#dbName,
|
||||
collectionName: this.name,
|
||||
options,
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
// Loaded from https://deno.land/x/ramda@v0.27.2/source/lensProp.js
|
||||
|
||||
|
||||
import _curry1 from './internal/_curry1.js';
|
||||
import assoc from './assoc.js';
|
||||
import lens from './lens.js';
|
||||
import prop from './prop.js';
|
||||
|
||||
|
||||
/**
|
||||
* Returns a lens whose focus is the specified property.
|
||||
*
|
||||
* @func
|
||||
* @memberOf R
|
||||
* @since v0.14.0
|
||||
* @category Object
|
||||
* @typedefn Lens s a = Functor f => (a -> f a) -> s -> f s
|
||||
* @sig String -> Lens s a
|
||||
* @param {String} k
|
||||
* @return {Lens}
|
||||
* @see R.view, R.set, R.over
|
||||
* @example
|
||||
*
|
||||
* const xLens = R.lensProp('x');
|
||||
*
|
||||
* R.view(xLens, {x: 1, y: 2}); //=> 1
|
||||
* R.set(xLens, 4, {x: 1, y: 2}); //=> {x: 4, y: 2}
|
||||
* R.over(xLens, R.negate, {x: 1, y: 2}); //=> {x: -1, y: 2}
|
||||
*/
|
||||
var lensProp = _curry1(function lensProp(k) {
|
||||
return lens(prop(k), assoc(k));
|
||||
});
|
||||
export default lensProp;
|
@ -0,0 +1,104 @@
|
||||
// Loaded from https://deno.land/std@0.78.0/encoding/_yaml/schema.ts
|
||||
|
||||
|
||||
// Ported from js-yaml v3.13.1:
|
||||
// https://github.com/nodeca/js-yaml/commit/665aadda42349dcae869f12040d9b10ef18d12da
|
||||
// Copyright 2011-2015 by Vitaly Puzrin. All rights reserved. MIT license.
|
||||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
import { YAMLError } from "./error.ts";
|
||||
import type { KindType, Type } from "./type.ts";
|
||||
import type { Any, ArrayObject } from "./utils.ts";
|
||||
|
||||
function compileList(
|
||||
schema: Schema,
|
||||
name: "implicit" | "explicit",
|
||||
result: Type[],
|
||||
): Type[] {
|
||||
const exclude: number[] = [];
|
||||
|
||||
for (const includedSchema of schema.include) {
|
||||
result = compileList(includedSchema, name, result);
|
||||
}
|
||||
|
||||
for (const currentType of schema[name]) {
|
||||
for (
|
||||
let previousIndex = 0;
|
||||
previousIndex < result.length;
|
||||
previousIndex++
|
||||
) {
|
||||
const previousType = result[previousIndex];
|
||||
if (
|
||||
previousType.tag === currentType.tag &&
|
||||
previousType.kind === currentType.kind
|
||||
) {
|
||||
exclude.push(previousIndex);
|
||||
}
|
||||
}
|
||||
|
||||
result.push(currentType);
|
||||
}
|
||||
|
||||
return result.filter((type, index): unknown => !exclude.includes(index));
|
||||
}
|
||||
|
||||
export type TypeMap = { [k in KindType | "fallback"]: ArrayObject<Type> };
|
||||
function compileMap(...typesList: Type[][]): TypeMap {
|
||||
const result: TypeMap = {
|
||||
fallback: {},
|
||||
mapping: {},
|
||||
scalar: {},
|
||||
sequence: {},
|
||||
};
|
||||
|
||||
for (const types of typesList) {
|
||||
for (const type of types) {
|
||||
if (type.kind !== null) {
|
||||
result[type.kind][type.tag] = result["fallback"][type.tag] = type;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export class Schema implements SchemaDefinition {
|
||||
public static SCHEMA_DEFAULT?: Schema;
|
||||
|
||||
public implicit: Type[];
|
||||
public explicit: Type[];
|
||||
public include: Schema[];
|
||||
|
||||
public compiledImplicit: Type[];
|
||||
public compiledExplicit: Type[];
|
||||
public compiledTypeMap: TypeMap;
|
||||
|
||||
constructor(definition: SchemaDefinition) {
|
||||
this.explicit = definition.explicit || [];
|
||||
this.implicit = definition.implicit || [];
|
||||
this.include = definition.include || [];
|
||||
|
||||
for (const type of this.implicit) {
|
||||
if (type.loadKind && type.loadKind !== "scalar") {
|
||||
throw new YAMLError(
|
||||
// eslint-disable-next-line max-len
|
||||
"There is a non-scalar type in the implicit list of a schema. Implicit resolving of such types is not supported.",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
this.compiledImplicit = compileList(this, "implicit", []);
|
||||
this.compiledExplicit = compileList(this, "explicit", []);
|
||||
this.compiledTypeMap = compileMap(
|
||||
this.compiledImplicit,
|
||||
this.compiledExplicit,
|
||||
);
|
||||
}
|
||||
|
||||
public static create(): void {}
|
||||
}
|
||||
|
||||
export interface SchemaDefinition {
|
||||
implicit?: Any[];
|
||||
explicit?: Type[];
|
||||
include?: Schema[];
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
// Loaded from https://deno.land/x/ramda@v0.27.2/source/pipe.js
|
||||
|
||||
|
||||
import _arity from './internal/_arity.js';
|
||||
import _pipe from './internal/_pipe.js';
|
||||
import reduce from './reduce.js';
|
||||
import tail from './tail.js';
|
||||
|
||||
|
||||
/**
|
||||
* Performs left-to-right function composition. The first argument may have
|
||||
* any arity; the remaining arguments must be unary.
|
||||
*
|
||||
* In some libraries this function is named `sequence`.
|
||||
*
|
||||
* **Note:** The result of pipe is not automatically curried.
|
||||
*
|
||||
* @func
|
||||
* @memberOf R
|
||||
* @since v0.1.0
|
||||
* @category Function
|
||||
* @sig (((a, b, ..., n) -> o), (o -> p), ..., (x -> y), (y -> z)) -> ((a, b, ..., n) -> z)
|
||||
* @param {...Function} functions
|
||||
* @return {Function}
|
||||
* @see R.compose
|
||||
* @example
|
||||
*
|
||||
* const f = R.pipe(Math.pow, R.negate, R.inc);
|
||||
*
|
||||
* f(3, 4); // -(3^4) + 1
|
||||
* @symb R.pipe(f, g, h)(a, b) = h(g(f(a, b)))
|
||||
* @symb R.pipe(f, g, h)(a)(b) = h(g(f(a)))(b)
|
||||
*/
|
||||
export default function pipe() {
|
||||
if (arguments.length === 0) {
|
||||
throw new Error('pipe requires at least one argument');
|
||||
}
|
||||
return _arity(
|
||||
arguments[0].length,
|
||||
reduce(_pipe, arguments[0], tail(arguments))
|
||||
);
|
||||
}
|
@ -0,0 +1,192 @@
|
||||
// Loaded from https://deno.land/std/log/logger.ts
|
||||
|
||||
|
||||
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
|
||||
import { getLevelByName, getLevelName, LogLevels } from "./levels.ts";
|
||||
import type { LevelName } from "./levels.ts";
|
||||
import type { BaseHandler } from "./handlers.ts";
|
||||
|
||||
// deno-lint-ignore no-explicit-any
|
||||
export type GenericFunction = (...args: any[]) => any;
|
||||
|
||||
export interface LogRecordOptions {
|
||||
msg: string;
|
||||
args: unknown[];
|
||||
level: number;
|
||||
loggerName: string;
|
||||
}
|
||||
|
||||
export class LogRecord {
|
||||
readonly msg: string;
|
||||
#args: unknown[];
|
||||
#datetime: Date;
|
||||
readonly level: number;
|
||||
readonly levelName: string;
|
||||
readonly loggerName: string;
|
||||
|
||||
constructor(options: LogRecordOptions) {
|
||||
this.msg = options.msg;
|
||||
this.#args = [...options.args];
|
||||
this.level = options.level;
|
||||
this.loggerName = options.loggerName;
|
||||
this.#datetime = new Date();
|
||||
this.levelName = getLevelName(options.level);
|
||||
}
|
||||
get args(): unknown[] {
|
||||
return [...this.#args];
|
||||
}
|
||||
get datetime(): Date {
|
||||
return new Date(this.#datetime.getTime());
|
||||
}
|
||||
}
|
||||
|
||||
export interface LoggerOptions {
|
||||
handlers?: BaseHandler[];
|
||||
}
|
||||
|
||||
export class Logger {
|
||||
#level: LogLevels;
|
||||
#handlers: BaseHandler[];
|
||||
readonly #loggerName: string;
|
||||
|
||||
constructor(
|
||||
loggerName: string,
|
||||
levelName: LevelName,
|
||||
options: LoggerOptions = {},
|
||||
) {
|
||||
this.#loggerName = loggerName;
|
||||
this.#level = getLevelByName(levelName);
|
||||
this.#handlers = options.handlers || [];
|
||||
}
|
||||
|
||||
get level(): LogLevels {
|
||||
return this.#level;
|
||||
}
|
||||
set level(level: LogLevels) {
|
||||
this.#level = level;
|
||||
}
|
||||
|
||||
get levelName(): LevelName {
|
||||
return getLevelName(this.#level);
|
||||
}
|
||||
set levelName(levelName: LevelName) {
|
||||
this.#level = getLevelByName(levelName);
|
||||
}
|
||||
|
||||
get loggerName(): string {
|
||||
return this.#loggerName;
|
||||
}
|
||||
|
||||
set handlers(hndls: BaseHandler[]) {
|
||||
this.#handlers = hndls;
|
||||
}
|
||||
get handlers(): BaseHandler[] {
|
||||
return this.#handlers;
|
||||
}
|
||||
|
||||
/** If the level of the logger is greater than the level to log, then nothing
|
||||
* is logged, otherwise a log record is passed to each log handler. `msg` data
|
||||
* passed in is returned. If a function is passed in, it is only evaluated
|
||||
* if the msg will be logged and the return value will be the result of the
|
||||
* function, not the function itself, unless the function isn't called, in which
|
||||
* case undefined is returned. All types are coerced to strings for logging.
|
||||
*/
|
||||
private _log<T>(
|
||||
level: number,
|
||||
msg: (T extends GenericFunction ? never : T) | (() => T),
|
||||
...args: unknown[]
|
||||
): T | undefined {
|
||||
if (this.level > level) {
|
||||
return msg instanceof Function ? undefined : msg;
|
||||
}
|
||||
|
||||
let fnResult: T | undefined;
|
||||
let logMessage: string;
|
||||
if (msg instanceof Function) {
|
||||
fnResult = msg();
|
||||
logMessage = this.asString(fnResult);
|
||||
} else {
|
||||
logMessage = this.asString(msg);
|
||||
}
|
||||
const record: LogRecord = new LogRecord({
|
||||
msg: logMessage,
|
||||
args: args,
|
||||
level: level,
|
||||
loggerName: this.loggerName,
|
||||
});
|
||||
|
||||
this.#handlers.forEach((handler): void => {
|
||||
handler.handle(record);
|
||||
});
|
||||
|
||||
return msg instanceof Function ? fnResult : msg;
|
||||
}
|
||||
|
||||
asString(data: unknown): string {
|
||||
if (typeof data === "string") {
|
||||
return data;
|
||||
} else if (
|
||||
data === null ||
|
||||
typeof data === "number" ||
|
||||
typeof data === "bigint" ||
|
||||
typeof data === "boolean" ||
|
||||
typeof data === "undefined" ||
|
||||
typeof data === "symbol"
|
||||
) {
|
||||
return String(data);
|
||||
} else if (data instanceof Error) {
|
||||
return data.stack!;
|
||||
} else if (typeof data === "object") {
|
||||
return JSON.stringify(data);
|
||||
}
|
||||
return "undefined";
|
||||
}
|
||||
|
||||
debug<T>(msg: () => T, ...args: unknown[]): T | undefined;
|
||||
debug<T>(msg: T extends GenericFunction ? never : T, ...args: unknown[]): T;
|
||||
debug<T>(
|
||||
msg: (T extends GenericFunction ? never : T) | (() => T),
|
||||
...args: unknown[]
|
||||
): T | undefined {
|
||||
return this._log(LogLevels.DEBUG, msg, ...args);
|
||||
}
|
||||
|
||||
info<T>(msg: () => T, ...args: unknown[]): T | undefined;
|
||||
info<T>(msg: T extends GenericFunction ? never : T, ...args: unknown[]): T;
|
||||
info<T>(
|
||||
msg: (T extends GenericFunction ? never : T) | (() => T),
|
||||
...args: unknown[]
|
||||
): T | undefined {
|
||||
return this._log(LogLevels.INFO, msg, ...args);
|
||||
}
|
||||
|
||||
warning<T>(msg: () => T, ...args: unknown[]): T | undefined;
|
||||
warning<T>(msg: T extends GenericFunction ? never : T, ...args: unknown[]): T;
|
||||
warning<T>(
|
||||
msg: (T extends GenericFunction ? never : T) | (() => T),
|
||||
...args: unknown[]
|
||||
): T | undefined {
|
||||
return this._log(LogLevels.WARNING, msg, ...args);
|
||||
}
|
||||
|
||||
error<T>(msg: () => T, ...args: unknown[]): T | undefined;
|
||||
error<T>(msg: T extends GenericFunction ? never : T, ...args: unknown[]): T;
|
||||
error<T>(
|
||||
msg: (T extends GenericFunction ? never : T) | (() => T),
|
||||
...args: unknown[]
|
||||
): T | undefined {
|
||||
return this._log(LogLevels.ERROR, msg, ...args);
|
||||
}
|
||||
|
||||
critical<T>(msg: () => T, ...args: unknown[]): T | undefined;
|
||||
critical<T>(
|
||||
msg: T extends GenericFunction ? never : T,
|
||||
...args: unknown[]
|
||||
): T;
|
||||
critical<T>(
|
||||
msg: (T extends GenericFunction ? never : T) | (() => T),
|
||||
...args: unknown[]
|
||||
): T | undefined {
|
||||
return this._log(LogLevels.CRITICAL, msg, ...args);
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
// Loaded from https://deno.land/std@0.80.0/encoding/_yaml/error.ts
|
||||
|
||||
|
||||
// Ported from js-yaml v3.13.1:
|
||||
// https://github.com/nodeca/js-yaml/commit/665aadda42349dcae869f12040d9b10ef18d12da
|
||||
// Copyright 2011-2015 by Vitaly Puzrin. All rights reserved. MIT license.
|
||||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
import type { Mark } from "./mark.ts";
|
||||
|
||||
export class YAMLError extends Error {
|
||||
constructor(
|
||||
message = "(unknown reason)",
|
||||
protected mark: Mark | string = "",
|
||||
) {
|
||||
super(`${message} ${mark}`);
|
||||
this.name = this.constructor.name;
|
||||
}
|
||||
|
||||
public toString(_compact: boolean): string {
|
||||
return `${this.name}: ${this.message} ${this.mark}`;
|
||||
}
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
// Loaded from https://deno.land/std@0.73.0/io/ioutil.ts
|
||||
|
||||
|
||||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
import type { BufReader } from "./bufio.ts";
|
||||
type Reader = Deno.Reader;
|
||||
type Writer = Deno.Writer;
|
||||
import { assert } from "../_util/assert.ts";
|
||||
|
||||
const DEFAULT_BUFFER_SIZE = 32 * 1024;
|
||||
|
||||
/** copy N size at the most.
|
||||
* If read size is lesser than N, then returns nread
|
||||
* */
|
||||
export async function copyN(
|
||||
r: Reader,
|
||||
dest: Writer,
|
||||
size: number,
|
||||
): Promise<number> {
|
||||
let bytesRead = 0;
|
||||
let buf = new Uint8Array(DEFAULT_BUFFER_SIZE);
|
||||
while (bytesRead < size) {
|
||||
if (size - bytesRead < DEFAULT_BUFFER_SIZE) {
|
||||
buf = new Uint8Array(size - bytesRead);
|
||||
}
|
||||
const result = await r.read(buf);
|
||||
const nread = result ?? 0;
|
||||
bytesRead += nread;
|
||||
if (nread > 0) {
|
||||
let n = 0;
|
||||
while (n < nread) {
|
||||
n += await dest.write(buf.slice(n, nread));
|
||||
}
|
||||
assert(n === nread, "could not write");
|
||||
}
|
||||
if (result === null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return bytesRead;
|
||||
}
|
||||
|
||||
/** Read big endian 16bit short from BufReader */
|
||||
export async function readShort(buf: BufReader): Promise<number | null> {
|
||||
const high = await buf.readByte();
|
||||
if (high === null) return null;
|
||||
const low = await buf.readByte();
|
||||
if (low === null) throw new Deno.errors.UnexpectedEof();
|
||||
return (high << 8) | low;
|
||||
}
|
||||
|
||||
/** Read big endian 32bit integer from BufReader */
|
||||
export async function readInt(buf: BufReader): Promise<number | null> {
|
||||
const high = await readShort(buf);
|
||||
if (high === null) return null;
|
||||
const low = await readShort(buf);
|
||||
if (low === null) throw new Deno.errors.UnexpectedEof();
|
||||
return (high << 16) | low;
|
||||
}
|
||||
|
||||
const MAX_SAFE_INTEGER = BigInt(Number.MAX_SAFE_INTEGER);
|
||||
|
||||
/** Read big endian 64bit long from BufReader */
|
||||
export async function readLong(buf: BufReader): Promise<number | null> {
|
||||
const high = await readInt(buf);
|
||||
if (high === null) return null;
|
||||
const low = await readInt(buf);
|
||||
if (low === null) throw new Deno.errors.UnexpectedEof();
|
||||
const big = (BigInt(high) << 32n) | BigInt(low);
|
||||
// We probably should provide a similar API that returns BigInt values.
|
||||
if (big > MAX_SAFE_INTEGER) {
|
||||
throw new RangeError(
|
||||
"Long value too big to be represented as a JavaScript number.",
|
||||
);
|
||||
}
|
||||
return Number(big);
|
||||
}
|
||||
|
||||
/** Slice number into 64bit big endian byte array */
|
||||
export function sliceLongToBytes(d: number, dest = new Array(8)): number[] {
|
||||
let big = BigInt(d);
|
||||
for (let i = 0; i < 8; i++) {
|
||||
dest[7 - i] = Number(big & 0xffn);
|
||||
big >>= 8n;
|
||||
}
|
||||
return dest;
|
||||
}
|
@ -0,0 +1,353 @@
|
||||
// Loaded from https://deno.land/x/oak@v6.3.1/cookies.ts
|
||||
|
||||
|
||||
// Copyright 2018-2020 the oak authors. All rights reserved. MIT license.
|
||||
|
||||
// This was heavily influenced by
|
||||
// [cookies](https://github.com/pillarjs/cookies/blob/master/index.js)
|
||||
|
||||
import type { KeyStack } from "./keyStack.ts";
|
||||
import type { Request } from "./request.ts";
|
||||
import type { Response } from "./response.ts";
|
||||
|
||||
export interface CookiesOptions {
|
||||
keys?: KeyStack;
|
||||
secure?: boolean;
|
||||
}
|
||||
|
||||
export interface CookiesGetOptions {
|
||||
signed?: boolean;
|
||||
}
|
||||
|
||||
export interface CookiesSetDeleteOptions {
|
||||
domain?: string;
|
||||
expires?: Date;
|
||||
httpOnly?: boolean;
|
||||
maxAge?: number;
|
||||
overwrite?: boolean;
|
||||
path?: string;
|
||||
secure?: boolean;
|
||||
sameSite?: "strict" | "lax" | "none" | boolean;
|
||||
signed?: boolean;
|
||||
}
|
||||
|
||||
type CookieAttributes = CookiesSetDeleteOptions;
|
||||
|
||||
const matchCache: Record<string, RegExp> = {};
|
||||
|
||||
// deno-lint-ignore no-control-regex
|
||||
const FIELD_CONTENT_REGEXP = /^[\u0009\u0020-\u007e\u0080-\u00ff]+$/;
|
||||
const KEY_REGEXP = /(?:^|;) *([^=]*)=[^;]*/g;
|
||||
const SAME_SITE_REGEXP = /^(?:lax|none|strict)$/i;
|
||||
|
||||
function getPattern(name: string): RegExp {
|
||||
if (name in matchCache) {
|
||||
return matchCache[name];
|
||||
}
|
||||
|
||||
return matchCache[name] = new RegExp(
|
||||
`(?:^|;) *${name.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&")}=([^;]*)`,
|
||||
);
|
||||
}
|
||||
|
||||
function pushCookie(headers: string[], cookie: Cookie): void {
|
||||
if (cookie.overwrite) {
|
||||
for (let i = headers.length - 1; i >= 0; i--) {
|
||||
if (headers[i].indexOf(`${cookie.name}=`) === 0) {
|
||||
headers.splice(i, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
headers.push(cookie.toHeader());
|
||||
}
|
||||
|
||||
function validateCookieProperty(
|
||||
key: string,
|
||||
value: string | undefined | null,
|
||||
): void {
|
||||
if (value && !FIELD_CONTENT_REGEXP.test(value)) {
|
||||
throw new TypeError(`The ${key} of the cookie (${value}) is invalid.`);
|
||||
}
|
||||
}
|
||||
|
||||
class Cookie implements CookieAttributes {
|
||||
domain?: string;
|
||||
expires?: Date;
|
||||
httpOnly = true;
|
||||
maxAge?: number;
|
||||
name: string;
|
||||
overwrite = false;
|
||||
path = "/";
|
||||
sameSite: "strict" | "lax" | "none" | boolean = false;
|
||||
secure = false;
|
||||
signed?: boolean;
|
||||
value: string;
|
||||
|
||||
/** A logical representation of a cookie, used to internally manage the
|
||||
* cookie instances. */
|
||||
constructor(
|
||||
name: string,
|
||||
value: string | null,
|
||||
attributes: CookieAttributes,
|
||||
) {
|
||||
validateCookieProperty("name", name);
|
||||
validateCookieProperty("value", value);
|
||||
this.name = name;
|
||||
this.value = value ?? "";
|
||||
Object.assign(this, attributes);
|
||||
if (!this.value) {
|
||||
this.expires = new Date(0);
|
||||
this.maxAge = undefined;
|
||||
}
|
||||
|
||||
validateCookieProperty("path", this.path);
|
||||
validateCookieProperty("domain", this.domain);
|
||||
if (
|
||||
this.sameSite && typeof this.sameSite === "string" &&
|
||||
!SAME_SITE_REGEXP.test(this.sameSite)
|
||||
) {
|
||||
throw new TypeError(
|
||||
`The sameSite of the cookie ("${this.sameSite}") is invalid.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
toHeader(): string {
|
||||
let header = this.toString();
|
||||
if (this.maxAge) {
|
||||
this.expires = new Date(Date.now() + (this.maxAge * 1000));
|
||||
}
|
||||
|
||||
if (this.path) {
|
||||
header += `; path=${this.path}`;
|
||||
}
|
||||
if (this.expires) {
|
||||
header += `; expires=${this.expires.toUTCString()}`;
|
||||
}
|
||||
if (this.domain) {
|
||||
header += `; domain=${this.domain}`;
|
||||
}
|
||||
if (this.sameSite) {
|
||||
header += `; samesite=${
|
||||
this.sameSite === true ? "strict" : this.sameSite.toLowerCase()
|
||||
}`;
|
||||
}
|
||||
if (this.secure) {
|
||||
header += "; secure";
|
||||
}
|
||||
if (this.httpOnly) {
|
||||
header += "; httponly";
|
||||
}
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return `${this.name}=${this.value}`;
|
||||
}
|
||||
}
|
||||
|
||||
/** An interface which allows setting and accessing cookies related to both the
|
||||
* current request and response. */
|
||||
export class Cookies {
|
||||
#cookieKeys?: string[];
|
||||
#keys?: KeyStack;
|
||||
#request: Request;
|
||||
#response: Response;
|
||||
#secure?: boolean;
|
||||
|
||||
#requestKeys = (): string[] => {
|
||||
if (this.#cookieKeys) {
|
||||
return this.#cookieKeys;
|
||||
}
|
||||
const result = this.#cookieKeys = [] as string[];
|
||||
const header = this.#request.headers.get("cookie");
|
||||
if (!header) {
|
||||
return result;
|
||||
}
|
||||
let matches: RegExpExecArray | null;
|
||||
while ((matches = KEY_REGEXP.exec(header))) {
|
||||
const [, key] = matches;
|
||||
result.push(key);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
constructor(
|
||||
request: Request,
|
||||
response: Response,
|
||||
options: CookiesOptions = {},
|
||||
) {
|
||||
const { keys, secure } = options;
|
||||
this.#keys = keys;
|
||||
this.#request = request;
|
||||
this.#response = response;
|
||||
this.#secure = secure;
|
||||
}
|
||||
|
||||
/** Set a cookie to be deleted in the response. This is a "shortcut" to
|
||||
* `.set(name, null, options?)`. */
|
||||
delete(name: string, options: CookiesSetDeleteOptions = {}): boolean {
|
||||
this.set(name, null, options);
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Iterate over the request's cookies, yielding up a tuple containing the
|
||||
* key and the value.
|
||||
*
|
||||
* If there are keys set on the application, only keys and values that are
|
||||
* properly signed will be returned. */
|
||||
*entries(): IterableIterator<[string, string]> {
|
||||
const keys = this.#requestKeys();
|
||||
for (const key of keys) {
|
||||
const value = this.get(key);
|
||||
if (value) {
|
||||
yield [key, value];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
forEach(
|
||||
callback: (key: string, value: string, cookies: this) => void,
|
||||
// deno-lint-ignore no-explicit-any
|
||||
thisArg: any = null,
|
||||
): void {
|
||||
const keys = this.#requestKeys();
|
||||
for (const key of keys) {
|
||||
const value = this.get(key);
|
||||
if (value) {
|
||||
callback.call(thisArg, key, value, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Get the value of a cookie from the request.
|
||||
*
|
||||
* If the cookie is signed, and the signature is invalid, the cookie will
|
||||
* be set to be deleted in the the response. If the signature uses an "old"
|
||||
* key, the cookie will be re-signed with the current key and be added to the
|
||||
* response to be updated. */
|
||||
get(name: string, options: CookiesGetOptions = {}): string | undefined {
|
||||
const signed = options.signed ?? !!this.#keys;
|
||||
const nameSig = `${name}.sig`;
|
||||
|
||||
const header = this.#request.headers.get("cookie");
|
||||
if (!header) {
|
||||
return;
|
||||
}
|
||||
const match = header.match(getPattern(name));
|
||||
if (!match) {
|
||||
return;
|
||||
}
|
||||
const [, value] = match;
|
||||
if (!signed) {
|
||||
return value;
|
||||
}
|
||||
const digest = this.get(nameSig, { signed: false });
|
||||
if (!digest) {
|
||||
return;
|
||||
}
|
||||
const data = `${name}=${value}`;
|
||||
if (!this.#keys) {
|
||||
throw new TypeError("keys required for signed cookies");
|
||||
}
|
||||
const index = this.#keys.indexOf(data, digest);
|
||||
|
||||
if (index < 0) {
|
||||
this.delete(nameSig, { path: "/", signed: false });
|
||||
} else {
|
||||
if (index) {
|
||||
// the key has "aged" and needs to be re-signed
|
||||
this.set(nameSig, this.#keys.sign(data), { signed: false });
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
/** Iterate over the request's cookies, yielding up the keys.
|
||||
*
|
||||
* If there are keys set on the application, only the keys that are properly
|
||||
* signed will be returned. */
|
||||
*keys(): IterableIterator<string> {
|
||||
const keys = this.#requestKeys();
|
||||
for (const key of keys) {
|
||||
const value = this.get(key);
|
||||
if (value) {
|
||||
yield key;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Set a cookie in the response.
|
||||
*
|
||||
* If there are keys set in the application, cookies will be automatically
|
||||
* signed, unless overridden by the set options. Cookies can be deleted by
|
||||
* setting the value to `null`. */
|
||||
set(
|
||||
name: string,
|
||||
value: string | null,
|
||||
options: CookiesSetDeleteOptions = {},
|
||||
): this {
|
||||
const request = this.#request;
|
||||
const response = this.#response;
|
||||
let headers = response.headers.get("Set-Cookie") ?? [] as string[];
|
||||
if (typeof headers === "string") {
|
||||
headers = [headers];
|
||||
}
|
||||
const secure = this.#secure !== undefined ? this.#secure : request.secure;
|
||||
const signed = options.signed ?? !!this.#keys;
|
||||
|
||||
if (!secure && options.secure) {
|
||||
throw new TypeError(
|
||||
"Cannot send secure cookie over unencrypted connection.",
|
||||
);
|
||||
}
|
||||
|
||||
const cookie = new Cookie(name, value, options);
|
||||
cookie.secure = options.secure ?? secure;
|
||||
pushCookie(headers, cookie);
|
||||
|
||||
if (signed) {
|
||||
if (!this.#keys) {
|
||||
throw new TypeError(".keys required for signed cookies.");
|
||||
}
|
||||
cookie.value = this.#keys.sign(cookie.toString());
|
||||
cookie.name += ".sig";
|
||||
pushCookie(headers, cookie);
|
||||
}
|
||||
|
||||
for (const header of headers) {
|
||||
response.headers.append("Set-Cookie", header);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Iterate over the request's cookies, yielding up each value.
|
||||
*
|
||||
* If there are keys set on the application, only the values that are
|
||||
* properly signed will be returned. */
|
||||
*values(): IterableIterator<string> {
|
||||
const keys = this.#requestKeys();
|
||||
for (const key of keys) {
|
||||
const value = this.get(key);
|
||||
if (value) {
|
||||
yield value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Iterate over the request's cookies, yielding up a tuple containing the
|
||||
* key and the value.
|
||||
*
|
||||
* If there are keys set on the application, only keys and values that are
|
||||
* properly signed will be returned. */
|
||||
*[Symbol.iterator](): IterableIterator<[string, string]> {
|
||||
const keys = this.#requestKeys();
|
||||
for (const key of keys) {
|
||||
const value = this.get(key);
|
||||
if (value) {
|
||||
yield [key, value];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
// Loaded from https://deno.land/x/god_crypto@v0.2.0/src/eme_oaep.ts
|
||||
|
||||
|
||||
import { createHash } from "https://deno.land/std/hash/mod.ts";
|
||||
import { mgf1 } from "./primitives.ts";
|
||||
import { concat, xor, random_bytes } from "./helper.ts";
|
||||
|
||||
/**
|
||||
* https://tools.ietf.org/html/rfc3447#page-10
|
||||
*
|
||||
* @param label
|
||||
* @param m
|
||||
* @param k
|
||||
* @param algorithm
|
||||
*/
|
||||
export function eme_oaep_encode(label: Uint8Array, m: Uint8Array, k: number, algorithm: "sha1" | "sha256"): Uint8Array {
|
||||
const labelHash = new Uint8Array(createHash(algorithm).update(label).digest());
|
||||
|
||||
const ps = new Uint8Array(k - labelHash.length * 2 - 2 - m.length);
|
||||
const db = concat(labelHash, ps, [0x01], m);
|
||||
const seed = random_bytes(labelHash.length);
|
||||
const dbMask = mgf1(seed, k - labelHash.length - 1, algorithm);
|
||||
const maskedDb = xor(db, dbMask);
|
||||
const seedMask = mgf1(maskedDb, labelHash.length, algorithm);
|
||||
const maskedSeed = xor(seed, seedMask);
|
||||
|
||||
return concat([0x00], maskedSeed, maskedDb);
|
||||
}
|
||||
|
||||
export function eme_oaep_decode(label: Uint8Array, c: Uint8Array, k: number, algorithm: "sha1" | "sha256"): Uint8Array {
|
||||
const labelHash = new Uint8Array(createHash(algorithm).update(label).digest());
|
||||
const maskedSeed = c.slice(1, 1 + labelHash.length);
|
||||
const maskedDb = c.slice(1 + labelHash.length);
|
||||
const seedMask = mgf1(maskedDb, labelHash.length, algorithm);
|
||||
const seed = xor(maskedSeed, seedMask);
|
||||
const dbMask = mgf1(seed, k - labelHash.length - 1, algorithm);
|
||||
const db = xor(maskedDb, dbMask);
|
||||
|
||||
let ptr = labelHash.length;
|
||||
while(ptr < db.length && db[ptr] === 0) ptr++;
|
||||
|
||||
return db.slice(ptr + 1);
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
// Loaded from https://deno.land/std@0.84.0/path/_constants.ts
|
||||
|
||||
|
||||
// Copyright the Browserify authors. MIT License.
|
||||
// Ported from https://github.com/browserify/path-browserify/
|
||||
// This module is browser compatible.
|
||||
|
||||
// Alphabet chars.
|
||||
export const CHAR_UPPERCASE_A = 65; /* A */
|
||||
export const CHAR_LOWERCASE_A = 97; /* a */
|
||||
export const CHAR_UPPERCASE_Z = 90; /* Z */
|
||||
export const CHAR_LOWERCASE_Z = 122; /* z */
|
||||
|
||||
// Non-alphabetic chars.
|
||||
export const CHAR_DOT = 46; /* . */
|
||||
export const CHAR_FORWARD_SLASH = 47; /* / */
|
||||
export const CHAR_BACKWARD_SLASH = 92; /* \ */
|
||||
export const CHAR_VERTICAL_LINE = 124; /* | */
|
||||
export const CHAR_COLON = 58; /* : */
|
||||
export const CHAR_QUESTION_MARK = 63; /* ? */
|
||||
export const CHAR_UNDERSCORE = 95; /* _ */
|
||||
export const CHAR_LINE_FEED = 10; /* \n */
|
||||
export const CHAR_CARRIAGE_RETURN = 13; /* \r */
|
||||
export const CHAR_TAB = 9; /* \t */
|
||||
export const CHAR_FORM_FEED = 12; /* \f */
|
||||
export const CHAR_EXCLAMATION_MARK = 33; /* ! */
|
||||
export const CHAR_HASH = 35; /* # */
|
||||
export const CHAR_SPACE = 32; /* */
|
||||
export const CHAR_NO_BREAK_SPACE = 160; /* \u00A0 */
|
||||
export const CHAR_ZERO_WIDTH_NOBREAK_SPACE = 65279; /* \uFEFF */
|
||||
export const CHAR_LEFT_SQUARE_BRACKET = 91; /* [ */
|
||||
export const CHAR_RIGHT_SQUARE_BRACKET = 93; /* ] */
|
||||
export const CHAR_LEFT_ANGLE_BRACKET = 60; /* < */
|
||||
export const CHAR_RIGHT_ANGLE_BRACKET = 62; /* > */
|
||||
export const CHAR_LEFT_CURLY_BRACKET = 123; /* { */
|
||||
export const CHAR_RIGHT_CURLY_BRACKET = 125; /* } */
|
||||
export const CHAR_HYPHEN_MINUS = 45; /* - */
|
||||
export const CHAR_PLUS = 43; /* + */
|
||||
export const CHAR_DOUBLE_QUOTE = 34; /* " */
|
||||
export const CHAR_SINGLE_QUOTE = 39; /* ' */
|
||||
export const CHAR_PERCENT = 37; /* % */
|
||||
export const CHAR_SEMICOLON = 59; /* ; */
|
||||
export const CHAR_CIRCUMFLEX_ACCENT = 94; /* ^ */
|
||||
export const CHAR_GRAVE_ACCENT = 96; /* ` */
|
||||
export const CHAR_AT = 64; /* @ */
|
||||
export const CHAR_AMPERSAND = 38; /* & */
|
||||
export const CHAR_EQUAL = 61; /* = */
|
||||
|
||||
// Digits
|
||||
export const CHAR_0 = 48; /* 0 */
|
||||
export const CHAR_9 = 57; /* 9 */
|
@ -0,0 +1,104 @@
|
||||
// Loaded from https://deno.land/std@0.80.0/encoding/_yaml/schema.ts
|
||||
|
||||
|
||||
// Ported from js-yaml v3.13.1:
|
||||
// https://github.com/nodeca/js-yaml/commit/665aadda42349dcae869f12040d9b10ef18d12da
|
||||
// Copyright 2011-2015 by Vitaly Puzrin. All rights reserved. MIT license.
|
||||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
import { YAMLError } from "./error.ts";
|
||||
import type { KindType, Type } from "./type.ts";
|
||||
import type { Any, ArrayObject } from "./utils.ts";
|
||||
|
||||
function compileList(
|
||||
schema: Schema,
|
||||
name: "implicit" | "explicit",
|
||||
result: Type[],
|
||||
): Type[] {
|
||||
const exclude: number[] = [];
|
||||
|
||||
for (const includedSchema of schema.include) {
|
||||
result = compileList(includedSchema, name, result);
|
||||
}
|
||||
|
||||
for (const currentType of schema[name]) {
|
||||
for (
|
||||
let previousIndex = 0;
|
||||
previousIndex < result.length;
|
||||
previousIndex++
|
||||
) {
|
||||
const previousType = result[previousIndex];
|
||||
if (
|
||||
previousType.tag === currentType.tag &&
|
||||
previousType.kind === currentType.kind
|
||||
) {
|
||||
exclude.push(previousIndex);
|
||||
}
|
||||
}
|
||||
|
||||
result.push(currentType);
|
||||
}
|
||||
|
||||
return result.filter((type, index): unknown => !exclude.includes(index));
|
||||
}
|
||||
|
||||
export type TypeMap = { [k in KindType | "fallback"]: ArrayObject<Type> };
|
||||
function compileMap(...typesList: Type[][]): TypeMap {
|
||||
const result: TypeMap = {
|
||||
fallback: {},
|
||||
mapping: {},
|
||||
scalar: {},
|
||||
sequence: {},
|
||||
};
|
||||
|
||||
for (const types of typesList) {
|
||||
for (const type of types) {
|
||||
if (type.kind !== null) {
|
||||
result[type.kind][type.tag] = result["fallback"][type.tag] = type;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export class Schema implements SchemaDefinition {
|
||||
public static SCHEMA_DEFAULT?: Schema;
|
||||
|
||||
public implicit: Type[];
|
||||
public explicit: Type[];
|
||||
public include: Schema[];
|
||||
|
||||
public compiledImplicit: Type[];
|
||||
public compiledExplicit: Type[];
|
||||
public compiledTypeMap: TypeMap;
|
||||
|
||||
constructor(definition: SchemaDefinition) {
|
||||
this.explicit = definition.explicit || [];
|
||||
this.implicit = definition.implicit || [];
|
||||
this.include = definition.include || [];
|
||||
|
||||
for (const type of this.implicit) {
|
||||
if (type.loadKind && type.loadKind !== "scalar") {
|
||||
throw new YAMLError(
|
||||
// eslint-disable-next-line max-len
|
||||
"There is a non-scalar type in the implicit list of a schema. Implicit resolving of such types is not supported.",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
this.compiledImplicit = compileList(this, "implicit", []);
|
||||
this.compiledExplicit = compileList(this, "explicit", []);
|
||||
this.compiledTypeMap = compileMap(
|
||||
this.compiledImplicit,
|
||||
this.compiledExplicit,
|
||||
);
|
||||
}
|
||||
|
||||
public static create(): void {}
|
||||
}
|
||||
|
||||
export interface SchemaDefinition {
|
||||
implicit?: Any[];
|
||||
explicit?: Type[];
|
||||
include?: Schema[];
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
// Loaded from https://deno.land/std@0.77.0/log/levels.ts
|
||||
|
||||
|
||||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
/** Get log level numeric values through enum constants
|
||||
*/
|
||||
export enum LogLevels {
|
||||
NOTSET = 0,
|
||||
DEBUG = 10,
|
||||
INFO = 20,
|
||||
WARNING = 30,
|
||||
ERROR = 40,
|
||||
CRITICAL = 50,
|
||||
}
|
||||
|
||||
/** Permitted log level names */
|
||||
export const LogLevelNames = Object.keys(LogLevels).filter((key) =>
|
||||
isNaN(Number(key))
|
||||
);
|
||||
|
||||
/** Union of valid log level strings */
|
||||
export type LevelName = keyof typeof LogLevels;
|
||||
|
||||
const byLevel: Record<string, LevelName> = {
|
||||
[String(LogLevels.NOTSET)]: "NOTSET",
|
||||
[String(LogLevels.DEBUG)]: "DEBUG",
|
||||
[String(LogLevels.INFO)]: "INFO",
|
||||
[String(LogLevels.WARNING)]: "WARNING",
|
||||
[String(LogLevels.ERROR)]: "ERROR",
|
||||
[String(LogLevels.CRITICAL)]: "CRITICAL",
|
||||
};
|
||||
|
||||
/** Returns the numeric log level associated with the passed,
|
||||
* stringy log level name.
|
||||
*/
|
||||
export function getLevelByName(name: LevelName): number {
|
||||
switch (name) {
|
||||
case "NOTSET":
|
||||
return LogLevels.NOTSET;
|
||||
case "DEBUG":
|
||||
return LogLevels.DEBUG;
|
||||
case "INFO":
|
||||
return LogLevels.INFO;
|
||||
case "WARNING":
|
||||
return LogLevels.WARNING;
|
||||
case "ERROR":
|
||||
return LogLevels.ERROR;
|
||||
case "CRITICAL":
|
||||
return LogLevels.CRITICAL;
|
||||
default:
|
||||
throw new Error(`no log level found for "${name}"`);
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns the stringy log level name provided the numeric log level */
|
||||
export function getLevelName(level: number): LevelName {
|
||||
const levelName = byLevel[level];
|
||||
if (levelName) {
|
||||
return levelName;
|
||||
}
|
||||
throw new Error(`no level name found for level: ${level}`);
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
// Loaded from https://deno.land/std@0.81.0/async/pool.ts
|
||||
|
||||
|
||||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
/**
|
||||
* pooledMap transforms values from an (async) iterable into another async
|
||||
* iterable. The transforms are done concurrently, with a max concurrency
|
||||
* defined by the poolLimit.
|
||||
*
|
||||
* @param poolLimit The maximum count of items being processed concurrently.
|
||||
* @param array The input array for mapping.
|
||||
* @param iteratorFn The function to call for every item of the array.
|
||||
*/
|
||||
export function pooledMap<T, R>(
|
||||
poolLimit: number,
|
||||
array: Iterable<T> | AsyncIterable<T>,
|
||||
iteratorFn: (data: T) => Promise<R>,
|
||||
): AsyncIterableIterator<R> {
|
||||
// Create the async iterable that is returned from this function.
|
||||
const res = new TransformStream<Promise<R>, R>({
|
||||
async transform(
|
||||
p: Promise<R>,
|
||||
controller: TransformStreamDefaultController<R>,
|
||||
): Promise<void> {
|
||||
controller.enqueue(await p);
|
||||
},
|
||||
});
|
||||
// Start processing items from the iterator
|
||||
(async (): Promise<void> => {
|
||||
const writer = res.writable.getWriter();
|
||||
const executing: Array<Promise<unknown>> = [];
|
||||
for await (const item of array) {
|
||||
const p = Promise.resolve().then(() => iteratorFn(item));
|
||||
writer.write(p);
|
||||
const e: Promise<unknown> = p.then(() =>
|
||||
executing.splice(executing.indexOf(e), 1)
|
||||
);
|
||||
executing.push(e);
|
||||
if (executing.length >= poolLimit) {
|
||||
await Promise.race(executing);
|
||||
}
|
||||
}
|
||||
// Wait until all ongoing events have processed, then close the writer.
|
||||
await Promise.all(executing);
|
||||
writer.close();
|
||||
})();
|
||||
return res.readable.getIterator();
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
// Loaded from https://deno.land/x/ramda@v0.27.2/source/internal/_isObject.js
|
||||
|
||||
|
||||
export default function _isObject(x) {
|
||||
return Object.prototype.toString.call(x) === '[object Object]';
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
// Loaded from https://deno.land/x/graphql_deno@v15.0.0/lib/utilities/assertValidName.js
|
||||
|
||||
|
||||
import devAssert from '../jsutils/devAssert.js';
|
||||
import { GraphQLError } from '../error/GraphQLError.js';
|
||||
const NAME_RX = /^[_a-zA-Z][_a-zA-Z0-9]*$/;
|
||||
/**
|
||||
* Upholds the spec rules about naming.
|
||||
*/
|
||||
|
||||
export function assertValidName(name) {
|
||||
const error = isValidNameError(name);
|
||||
|
||||
if (error) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
/**
|
||||
* Returns an Error if a name is invalid.
|
||||
*/
|
||||
|
||||
export function isValidNameError(name) {
|
||||
devAssert(typeof name === 'string', 'Expected name to be a string.');
|
||||
|
||||
if (name.length > 1 && name[0] === '_' && name[1] === '_') {
|
||||
return new GraphQLError(`Name "${name}" must not begin with "__", which is reserved by GraphQL introspection.`);
|
||||
}
|
||||
|
||||
if (!NAME_RX.test(name)) {
|
||||
return new GraphQLError(`Names must match /^[_a-zA-Z][_a-zA-Z0-9]*$/ but "${name}" does not.`);
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
// Loaded from https://deno.land/std@0.67.0/path/separator.ts
|
||||
|
||||
|
||||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
/** This module is browser compatible. */
|
||||
|
||||
import { isWindows } from "./_constants.ts";
|
||||
|
||||
export const SEP = isWindows ? "\\" : "/";
|
||||
export const SEP_PATTERN = isWindows ? /[\\/]+/ : /\/+/;
|
@ -0,0 +1,46 @@
|
||||
// Loaded from https://deno.land/x/graphql_deno@v15.0.0/lib/validation/rules/NoUnusedVariablesRule.js
|
||||
|
||||
|
||||
import { GraphQLError } from '../../error/GraphQLError.js';
|
||||
|
||||
/**
|
||||
* No unused variables
|
||||
*
|
||||
* A GraphQL operation is only valid if all variables defined by an operation
|
||||
* are used, either directly or within a spread fragment.
|
||||
*/
|
||||
export function NoUnusedVariablesRule(context) {
|
||||
let variableDefs = [];
|
||||
return {
|
||||
OperationDefinition: {
|
||||
enter() {
|
||||
variableDefs = [];
|
||||
},
|
||||
|
||||
leave(operation) {
|
||||
const variableNameUsed = Object.create(null);
|
||||
const usages = context.getRecursiveVariableUsages(operation);
|
||||
|
||||
for (const {
|
||||
node
|
||||
} of usages) {
|
||||
variableNameUsed[node.name.value] = true;
|
||||
}
|
||||
|
||||
for (const variableDef of variableDefs) {
|
||||
const variableName = variableDef.variable.name.value;
|
||||
|
||||
if (variableNameUsed[variableName] !== true) {
|
||||
context.reportError(new GraphQLError(operation.name ? `Variable "$${variableName}" is never used in operation "${operation.name.value}".` : `Variable "$${variableName}" is never used.`, variableDef));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
VariableDefinition(def) {
|
||||
variableDefs.push(def);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
// Loaded from https://deno.land/std@0.85.0/path/_interface.ts
|
||||
|
||||
|
||||
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
|
||||
// This module is browser compatible.
|
||||
|
||||
/**
|
||||
* A parsed path object generated by path.parse() or consumed by path.format().
|
||||
*/
|
||||
export interface ParsedPath {
|
||||
/**
|
||||
* The root of the path such as '/' or 'c:\'
|
||||
*/
|
||||
root: string;
|
||||
/**
|
||||
* The full directory path such as '/home/user/dir' or 'c:\path\dir'
|
||||
*/
|
||||
dir: string;
|
||||
/**
|
||||
* The file name including extension (if any) such as 'index.html'
|
||||
*/
|
||||
base: string;
|
||||
/**
|
||||
* The file extension (if any) such as '.html'
|
||||
*/
|
||||
ext: string;
|
||||
/**
|
||||
* The file name without extension (if any) such as 'index'
|
||||
*/
|
||||
name: string;
|
||||
}
|
||||
|
||||
export type FormatInputPathObject = Partial<ParsedPath>;
|
@ -0,0 +1,132 @@
|
||||
// Loaded from https://deno.land/x/segno@v1.1.0/lib/validations/isTaxID.ts
|
||||
|
||||
|
||||
/**
|
||||
* An Employer Identification Number (EIN), also known as a Federal Tax Identification Number,
|
||||
* is used to identify a business entity.
|
||||
*
|
||||
* NOTES:
|
||||
* - Prefix 47 is being reserved for future use
|
||||
* - Prefixes 26, 27, 45, 46 and 47 were previously assigned by the Philadelphia campus.
|
||||
*
|
||||
* See `http://www.irs.gov/Businesses/Small-Businesses-&-Self-Employed/How-EINs-are-Assigned-and-Valid-EIN-Prefixes`
|
||||
* for more information.
|
||||
*/
|
||||
|
||||
// @ts-ignore allowing typedoc to build
|
||||
import { assertString } from '../helpers/assertString.ts';
|
||||
|
||||
/**
|
||||
* Campus prefixes according to locales
|
||||
*/
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
const campusPrefix = {
|
||||
'en-US': {
|
||||
andover: ['10', '12'],
|
||||
atlanta: ['60', '67'],
|
||||
austin: ['50', '53'],
|
||||
brookhaven: [
|
||||
'01',
|
||||
'02',
|
||||
'03',
|
||||
'04',
|
||||
'05',
|
||||
'06',
|
||||
'11',
|
||||
'13',
|
||||
'14',
|
||||
'16',
|
||||
'21',
|
||||
'22',
|
||||
'23',
|
||||
'25',
|
||||
'34',
|
||||
'51',
|
||||
'52',
|
||||
'54',
|
||||
'55',
|
||||
'56',
|
||||
'57',
|
||||
'58',
|
||||
'59',
|
||||
'65',
|
||||
],
|
||||
cincinnati: ['30', '32', '35', '36', '37', '38', '61'],
|
||||
fresno: ['15', '24'],
|
||||
internet: ['20', '26', '27', '45', '46', '47'],
|
||||
kansas: ['40', '44'],
|
||||
memphis: ['94', '95'],
|
||||
ogden: ['80', '90'],
|
||||
philadelphia: [
|
||||
'33',
|
||||
'39',
|
||||
'41',
|
||||
'42',
|
||||
'43',
|
||||
'46',
|
||||
'48',
|
||||
'62',
|
||||
'63',
|
||||
'64',
|
||||
'66',
|
||||
'68',
|
||||
'71',
|
||||
'72',
|
||||
'73',
|
||||
'74',
|
||||
'75',
|
||||
'76',
|
||||
'77',
|
||||
'81',
|
||||
'82',
|
||||
'83',
|
||||
'84',
|
||||
'85',
|
||||
'86',
|
||||
'87',
|
||||
'88',
|
||||
'91',
|
||||
'92',
|
||||
'93',
|
||||
'98',
|
||||
'99',
|
||||
],
|
||||
sba: ['31'],
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
const getPrefixes = (locale: string) => {
|
||||
const prefixes = [];
|
||||
|
||||
for (const location in (campusPrefix as any)[locale]) {
|
||||
if ((campusPrefix as any)[locale].hasOwnProperty(location)) {
|
||||
prefixes.push(...(campusPrefix as any)[locale][location]);
|
||||
}
|
||||
}
|
||||
|
||||
prefixes.sort();
|
||||
|
||||
return prefixes;
|
||||
};
|
||||
|
||||
// tax id regex formats for various loacles
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
const taxIdFormat = {
|
||||
'en-US': /^\d{2}[- ]{0,1}\d{7}$/,
|
||||
};
|
||||
|
||||
export const isTaxID = (str: string, locale = 'en-US') => {
|
||||
assertString(str);
|
||||
if (!(taxIdFormat as any)[locale].test(str)) {
|
||||
return false;
|
||||
}
|
||||
return getPrefixes(locale).indexOf(str.substr(0, 2)) !== -1;
|
||||
};
|
@ -0,0 +1,72 @@
|
||||
// Loaded from https://deno.land/std@0.73.0/async/mux_async_iterator.ts
|
||||
|
||||
|
||||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
import { Deferred, deferred } from "./deferred.ts";
|
||||
|
||||
interface TaggedYieldedValue<T> {
|
||||
iterator: AsyncIterableIterator<T>;
|
||||
value: T;
|
||||
}
|
||||
|
||||
/** The MuxAsyncIterator class multiplexes multiple async iterators into a
|
||||
* single stream. It currently makes an assumption:
|
||||
* - The final result (the value returned and not yielded from the iterator)
|
||||
* does not matter; if there is any, it is discarded.
|
||||
*/
|
||||
export class MuxAsyncIterator<T> implements AsyncIterable<T> {
|
||||
private iteratorCount = 0;
|
||||
private yields: Array<TaggedYieldedValue<T>> = [];
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
private throws: any[] = [];
|
||||
private signal: Deferred<void> = deferred();
|
||||
|
||||
add(iterator: AsyncIterableIterator<T>): void {
|
||||
++this.iteratorCount;
|
||||
this.callIteratorNext(iterator);
|
||||
}
|
||||
|
||||
private async callIteratorNext(
|
||||
iterator: AsyncIterableIterator<T>,
|
||||
): Promise<void> {
|
||||
try {
|
||||
const { value, done } = await iterator.next();
|
||||
if (done) {
|
||||
--this.iteratorCount;
|
||||
} else {
|
||||
this.yields.push({ iterator, value });
|
||||
}
|
||||
} catch (e) {
|
||||
this.throws.push(e);
|
||||
}
|
||||
this.signal.resolve();
|
||||
}
|
||||
|
||||
async *iterate(): AsyncIterableIterator<T> {
|
||||
while (this.iteratorCount > 0) {
|
||||
// Sleep until any of the wrapped iterators yields.
|
||||
await this.signal;
|
||||
|
||||
// Note that while we're looping over `yields`, new items may be added.
|
||||
for (let i = 0; i < this.yields.length; i++) {
|
||||
const { iterator, value } = this.yields[i];
|
||||
yield value;
|
||||
this.callIteratorNext(iterator);
|
||||
}
|
||||
|
||||
if (this.throws.length) {
|
||||
for (const e of this.throws) {
|
||||
throw e;
|
||||
}
|
||||
this.throws.length = 0;
|
||||
}
|
||||
// Clear the `yields` list and reset the `signal` promise.
|
||||
this.yields.length = 0;
|
||||
this.signal = deferred();
|
||||
}
|
||||
}
|
||||
|
||||
[Symbol.asyncIterator](): AsyncIterableIterator<T> {
|
||||
return this.iterate();
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
// Loaded from https://deno.land/x/segno@v1.1.0/mod.ts
|
||||
|
||||
|
||||
import * as segno from './lib/index.ts';
|
||||
|
||||
// exporting all functions
|
||||
export * from './lib/index.ts';
|
||||
|
||||
// exporting functions namespaced to segno
|
||||
export { segno };
|
@ -0,0 +1,10 @@
|
||||
// Loaded from https://deno.land/std@0.80.0/path/separator.ts
|
||||
|
||||
|
||||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
/** This module is browser compatible. */
|
||||
|
||||
import { isWindows } from "../_util/os.ts";
|
||||
|
||||
export const SEP = isWindows ? "\\" : "/";
|
||||
export const SEP_PATTERN = isWindows ? /[\\/]+/ : /\/+/;
|
@ -0,0 +1,32 @@
|
||||
// Loaded from https://deno.land/x/colorlog@v1.0/mod.ts
|
||||
|
||||
|
||||
const reset: String = "\x1b[0m";
|
||||
const red: String = "\x1b[31m";
|
||||
const green: String = "\x1b[32m";
|
||||
const yellow: String = "\x1b[33m";
|
||||
|
||||
function error(val: any) {
|
||||
return (red + val + reset);
|
||||
}
|
||||
|
||||
function success(val: any) {
|
||||
return (green + val + reset);
|
||||
}
|
||||
|
||||
function warning(val: any) {
|
||||
return (yellow + val + reset);
|
||||
}
|
||||
function errorLog(val: any) {
|
||||
console.log(red + val + reset);
|
||||
}
|
||||
|
||||
function successLog(val: any) {
|
||||
console.log(green + val + reset);
|
||||
}
|
||||
|
||||
function warningLog(val: any) {
|
||||
console.log(yellow + val + reset);
|
||||
}
|
||||
|
||||
export { error, success, warning, errorLog, successLog, warningLog };
|
@ -0,0 +1,35 @@
|
||||
// Loaded from https://deno.land/x/ramda@v0.27.2/source/toPairs.js
|
||||
|
||||
|
||||
import _curry1 from './internal/_curry1.js';
|
||||
import _has from './internal/_has.js';
|
||||
|
||||
|
||||
/**
|
||||
* Converts an object into an array of key, value arrays. Only the object's
|
||||
* own properties are used.
|
||||
* Note that the order of the output array is not guaranteed to be consistent
|
||||
* across different JS platforms.
|
||||
*
|
||||
* @func
|
||||
* @memberOf R
|
||||
* @since v0.4.0
|
||||
* @category Object
|
||||
* @sig {String: *} -> [[String,*]]
|
||||
* @param {Object} obj The object to extract from
|
||||
* @return {Array} An array of key, value arrays from the object's own properties.
|
||||
* @see R.fromPairs
|
||||
* @example
|
||||
*
|
||||
* R.toPairs({a: 1, b: 2, c: 3}); //=> [['a', 1], ['b', 2], ['c', 3]]
|
||||
*/
|
||||
var toPairs = _curry1(function toPairs(obj) {
|
||||
var pairs = [];
|
||||
for (var prop in obj) {
|
||||
if (_has(prop, obj)) {
|
||||
pairs[pairs.length] = [prop, obj[prop]];
|
||||
}
|
||||
}
|
||||
return pairs;
|
||||
});
|
||||
export default toPairs;
|
@ -0,0 +1,19 @@
|
||||
// Loaded from https://deno.land/x/ramda@v0.27.2/source/internal/_xfilter.js
|
||||
|
||||
|
||||
import _curry2 from './_curry2.js';
|
||||
import _xfBase from './_xfBase.js';
|
||||
|
||||
|
||||
function XFilter(f, xf) {
|
||||
this.xf = xf;
|
||||
this.f = f;
|
||||
}
|
||||
XFilter.prototype['@@transducer/init'] = _xfBase.init;
|
||||
XFilter.prototype['@@transducer/result'] = _xfBase.result;
|
||||
XFilter.prototype['@@transducer/step'] = function(result, input) {
|
||||
return this.f(input) ? this.xf['@@transducer/step'](result, input) : result;
|
||||
};
|
||||
|
||||
var _xfilter = _curry2(function _xfilter(f, xf) { return new XFilter(f, xf); });
|
||||
export default _xfilter;
|
@ -0,0 +1,37 @@
|
||||
// Loaded from https://deno.land/x/ramda@v0.27.2/source/propEq.js
|
||||
|
||||
|
||||
import _curry3 from './internal/_curry3.js';
|
||||
import prop from './prop.js';
|
||||
import equals from './equals.js';
|
||||
|
||||
|
||||
/**
|
||||
* Returns `true` if the specified object property is equal, in
|
||||
* [`R.equals`](#equals) terms, to the given value; `false` otherwise.
|
||||
* You can test multiple properties with [`R.whereEq`](#whereEq).
|
||||
*
|
||||
* @func
|
||||
* @memberOf R
|
||||
* @since v0.1.0
|
||||
* @category Relation
|
||||
* @sig String -> a -> Object -> Boolean
|
||||
* @param {String} name
|
||||
* @param {*} val
|
||||
* @param {*} obj
|
||||
* @return {Boolean}
|
||||
* @see R.whereEq, R.propSatisfies, R.equals
|
||||
* @example
|
||||
*
|
||||
* const abby = {name: 'Abby', age: 7, hair: 'blond'};
|
||||
* const fred = {name: 'Fred', age: 12, hair: 'brown'};
|
||||
* const rusty = {name: 'Rusty', age: 10, hair: 'brown'};
|
||||
* const alois = {name: 'Alois', age: 15, disposition: 'surly'};
|
||||
* const kids = [abby, fred, rusty, alois];
|
||||
* const hasBrownHair = R.propEq('hair', 'brown');
|
||||
* R.filter(hasBrownHair, kids); //=> [fred, rusty]
|
||||
*/
|
||||
var propEq = _curry3(function propEq(name, val, obj) {
|
||||
return equals(val, prop(name, obj));
|
||||
});
|
||||
export default propEq;
|
@ -0,0 +1,23 @@
|
||||
// Loaded from https://deno.land/x/ramda@v0.27.2/source/internal/_xdrop.js
|
||||
|
||||
|
||||
import _curry2 from './_curry2.js';
|
||||
import _xfBase from './_xfBase.js';
|
||||
|
||||
|
||||
function XDrop(n, xf) {
|
||||
this.xf = xf;
|
||||
this.n = n;
|
||||
}
|
||||
XDrop.prototype['@@transducer/init'] = _xfBase.init;
|
||||
XDrop.prototype['@@transducer/result'] = _xfBase.result;
|
||||
XDrop.prototype['@@transducer/step'] = function(result, input) {
|
||||
if (this.n > 0) {
|
||||
this.n -= 1;
|
||||
return result;
|
||||
}
|
||||
return this.xf['@@transducer/step'](result, input);
|
||||
};
|
||||
|
||||
var _xdrop = _curry2(function _xdrop(n, xf) { return new XDrop(n, xf); });
|
||||
export default _xdrop;
|
@ -0,0 +1,9 @@
|
||||
// Loaded from https://deno.land/x/case@v2.1.0/constantCase.ts
|
||||
|
||||
|
||||
import upperCase from "./upperCase.ts";
|
||||
import snakeCase from "./snakeCase.ts";
|
||||
|
||||
export default function constantCase(value: string, locale?: string): string {
|
||||
return upperCase(snakeCase(value, locale), locale);
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
// Loaded from https://deno.land/x/segno@v1.1.0/lib/validations/isMimeType.ts
|
||||
|
||||
|
||||
/*
|
||||
Checks if the provided string matches to a correct Media type format (MIME type)
|
||||
|
||||
This function only checks is the string format follows the
|
||||
etablished rules by the according RFC specifications.
|
||||
This function supports 'charset' in textual media types
|
||||
(https://tools.ietf.org/html/rfc6657).
|
||||
|
||||
This function does not check against all the media types listed
|
||||
by the IANA (https://www.iana.org/assignments/media-types/media-types.xhtml)
|
||||
because of lightness purposes : it would require to include
|
||||
all these MIME types in this librairy, which would weigh it
|
||||
significantly. This kind of effort maybe is not worth for the use that
|
||||
this function has in this entire librairy.
|
||||
|
||||
More informations in the RFC specifications :
|
||||
- https://tools.ietf.org/html/rfc2045
|
||||
- https://tools.ietf.org/html/rfc2046
|
||||
- https://tools.ietf.org/html/rfc7231#section-3.1.1.1
|
||||
- https://tools.ietf.org/html/rfc7231#section-3.1.1.5
|
||||
*/
|
||||
|
||||
// @ts-ignore allowing typedoc to build
|
||||
import { assertString } from '../helpers/assertString.ts';
|
||||
|
||||
// Match simple MIME types
|
||||
// NB :
|
||||
// Subtype length must not exceed 100 characters.
|
||||
// This rule does not comply to the RFC specs (what is the max length ?).
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
const mimeTypeSimple = /^(application|audio|font|image|message|model|multipart|text|video)\/[a-zA-Z0-9\.\-\+]{1,100}$/i; // eslint-disable-line max-len
|
||||
|
||||
// Handle "charset" in "text/*"
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
const mimeTypeText = /^text\/[a-zA-Z0-9\.\-\+]{1,100};\s?charset=("[a-zA-Z0-9\.\-\+\s]{0,70}"|[a-zA-Z0-9\.\-\+]{0,70})(\s?\([a-zA-Z0-9\.\-\+\s]{1,20}\))?$/i; // eslint-disable-line max-len
|
||||
|
||||
// Handle "boundary" in "multipart/*"
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
const mimeTypeMultipart = /^multipart\/[a-zA-Z0-9\.\-\+]{1,100}(;\s?(boundary|charset)=("[a-zA-Z0-9\.\-\+\s]{0,70}"|[a-zA-Z0-9\.\-\+]{0,70})(\s?\([a-zA-Z0-9\.\-\+\s]{1,20}\))?){0,2}$/i; // eslint-disable-line max-len
|
||||
|
||||
export const isMimeType = (str: string) => {
|
||||
assertString(str);
|
||||
return (
|
||||
mimeTypeSimple.test(str) ||
|
||||
mimeTypeText.test(str) ||
|
||||
mimeTypeMultipart.test(str)
|
||||
);
|
||||
};
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,24 @@
|
||||
// Loaded from https://deno.land/std@0.78.0/encoding/_yaml/stringify.ts
|
||||
|
||||
|
||||
// Ported from js-yaml v3.13.1:
|
||||
// https://github.com/nodeca/js-yaml/commit/665aadda42349dcae869f12040d9b10ef18d12da
|
||||
// Copyright 2011-2015 by Vitaly Puzrin. All rights reserved. MIT license.
|
||||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
import { dump } from "./dumper/dumper.ts";
|
||||
import type { DumperStateOptions } from "./dumper/dumper_state.ts";
|
||||
|
||||
export type DumpOptions = DumperStateOptions;
|
||||
|
||||
/**
|
||||
* Serializes `object` as a YAML document.
|
||||
*
|
||||
* You can disable exceptions by setting the skipInvalid option to true.
|
||||
*/
|
||||
export function stringify(
|
||||
obj: Record<string, unknown>,
|
||||
options?: DumpOptions,
|
||||
): string {
|
||||
return dump(obj, options);
|
||||
}
|
@ -0,0 +1,143 @@
|
||||
// Loaded from https://deno.land/x/graphql_deno@v15.0.0/lib/graphql.js
|
||||
|
||||
|
||||
import isPromise from './jsutils/isPromise.js';
|
||||
import { parse } from './language/parser.js';
|
||||
import { validate } from './validation/validate.js';
|
||||
import { validateSchema } from './type/validate.js';
|
||||
import { execute } from './execution/execute.js';
|
||||
/**
|
||||
* This is the primary entry point function for fulfilling GraphQL operations
|
||||
* by parsing, validating, and executing a GraphQL document along side a
|
||||
* GraphQL schema.
|
||||
*
|
||||
* More sophisticated GraphQL servers, such as those which persist queries,
|
||||
* may wish to separate the validation and execution phases to a static time
|
||||
* tooling step, and a server runtime step.
|
||||
*
|
||||
* Accepts either an object with named arguments, or individual arguments:
|
||||
*
|
||||
* schema:
|
||||
* The GraphQL type system to use when validating and executing a query.
|
||||
* source:
|
||||
* A GraphQL language formatted string representing the requested operation.
|
||||
* rootValue:
|
||||
* The value provided as the first argument to resolver functions on the top
|
||||
* level type (e.g. the query object type).
|
||||
* contextValue:
|
||||
* The context value is provided as an argument to resolver functions after
|
||||
* field arguments. It is used to pass shared information useful at any point
|
||||
* during executing this query, for example the currently logged in user and
|
||||
* connections to databases or other services.
|
||||
* variableValues:
|
||||
* A mapping of variable name to runtime value to use for all variables
|
||||
* defined in the requestString.
|
||||
* operationName:
|
||||
* The name of the operation to use if requestString contains multiple
|
||||
* possible operations. Can be omitted if requestString contains only
|
||||
* one operation.
|
||||
* fieldResolver:
|
||||
* A resolver function to use when one is not provided by the schema.
|
||||
* If not provided, the default field resolver is used (which looks for a
|
||||
* value or method on the source value with the field's name).
|
||||
* typeResolver:
|
||||
* A type resolver function to use when none is provided by the schema.
|
||||
* If not provided, the default type resolver is used (which looks for a
|
||||
* `__typename` field or alternatively calls the `isTypeOf` method).
|
||||
*/
|
||||
|
||||
export function graphql(argsOrSchema, source, rootValue, contextValue, variableValues, operationName, fieldResolver, typeResolver) {
|
||||
/* eslint-enable no-redeclare */
|
||||
// Always return a Promise for a consistent API.
|
||||
return new Promise(resolve => resolve( // Extract arguments from object args if provided.
|
||||
arguments.length === 1 ? graphqlImpl(argsOrSchema) : graphqlImpl({
|
||||
schema: argsOrSchema,
|
||||
source,
|
||||
rootValue,
|
||||
contextValue,
|
||||
variableValues,
|
||||
operationName,
|
||||
fieldResolver,
|
||||
typeResolver
|
||||
})));
|
||||
}
|
||||
/**
|
||||
* The graphqlSync function also fulfills GraphQL operations by parsing,
|
||||
* validating, and executing a GraphQL document along side a GraphQL schema.
|
||||
* However, it guarantees to complete synchronously (or throw an error) assuming
|
||||
* that all field resolvers are also synchronous.
|
||||
*/
|
||||
|
||||
export function graphqlSync(argsOrSchema, source, rootValue, contextValue, variableValues, operationName, fieldResolver, typeResolver) {
|
||||
/* eslint-enable no-redeclare */
|
||||
// Extract arguments from object args if provided.
|
||||
const result = arguments.length === 1 ? graphqlImpl(argsOrSchema) : graphqlImpl({
|
||||
schema: argsOrSchema,
|
||||
source,
|
||||
rootValue,
|
||||
contextValue,
|
||||
variableValues,
|
||||
operationName,
|
||||
fieldResolver,
|
||||
typeResolver
|
||||
}); // Assert that the execution was synchronous.
|
||||
|
||||
if (isPromise(result)) {
|
||||
throw new Error('GraphQL execution failed to complete synchronously.');
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function graphqlImpl(args) {
|
||||
const {
|
||||
schema,
|
||||
source,
|
||||
rootValue,
|
||||
contextValue,
|
||||
variableValues,
|
||||
operationName,
|
||||
fieldResolver,
|
||||
typeResolver
|
||||
} = args; // Validate Schema
|
||||
|
||||
const schemaValidationErrors = validateSchema(schema);
|
||||
|
||||
if (schemaValidationErrors.length > 0) {
|
||||
return {
|
||||
errors: schemaValidationErrors
|
||||
};
|
||||
} // Parse
|
||||
|
||||
|
||||
let document;
|
||||
|
||||
try {
|
||||
document = parse(source);
|
||||
} catch (syntaxError) {
|
||||
return {
|
||||
errors: [syntaxError]
|
||||
};
|
||||
} // Validate
|
||||
|
||||
|
||||
const validationErrors = validate(schema, document);
|
||||
|
||||
if (validationErrors.length > 0) {
|
||||
return {
|
||||
errors: validationErrors
|
||||
};
|
||||
} // Execute
|
||||
|
||||
|
||||
return execute({
|
||||
schema,
|
||||
document,
|
||||
rootValue,
|
||||
contextValue,
|
||||
variableValues,
|
||||
operationName,
|
||||
fieldResolver,
|
||||
typeResolver
|
||||
});
|
||||
}
|
File diff suppressed because one or more lines are too long
@ -0,0 +1,19 @@
|
||||
// Loaded from https://deno.land/x/ramda@v0.27.2/source/internal/_xmap.js
|
||||
|
||||
|
||||
import _curry2 from './_curry2.js';
|
||||
import _xfBase from './_xfBase.js';
|
||||
|
||||
|
||||
function XMap(f, xf) {
|
||||
this.xf = xf;
|
||||
this.f = f;
|
||||
}
|
||||
XMap.prototype['@@transducer/init'] = _xfBase.init;
|
||||
XMap.prototype['@@transducer/result'] = _xfBase.result;
|
||||
XMap.prototype['@@transducer/step'] = function(result, input) {
|
||||
return this.xf['@@transducer/step'](result, this.f(input));
|
||||
};
|
||||
|
||||
var _xmap = _curry2(function _xmap(f, xf) { return new XMap(f, xf); });
|
||||
export default _xmap;
|
@ -0,0 +1,45 @@
|
||||
// Loaded from https://deno.land/std@0.77.0/io/writers.ts
|
||||
|
||||
|
||||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
type Writer = Deno.Writer;
|
||||
type WriterSync = Deno.WriterSync;
|
||||
import { decode, encode } from "../encoding/utf8.ts";
|
||||
|
||||
/** Writer utility for buffering string chunks */
|
||||
export class StringWriter implements Writer, WriterSync {
|
||||
private chunks: Uint8Array[] = [];
|
||||
private byteLength = 0;
|
||||
private cache: string | undefined;
|
||||
|
||||
constructor(private base: string = "") {
|
||||
const c = encode(base);
|
||||
this.chunks.push(c);
|
||||
this.byteLength += c.byteLength;
|
||||
}
|
||||
|
||||
write(p: Uint8Array): Promise<number> {
|
||||
return Promise.resolve(this.writeSync(p));
|
||||
}
|
||||
|
||||
writeSync(p: Uint8Array): number {
|
||||
this.chunks.push(p);
|
||||
this.byteLength += p.byteLength;
|
||||
this.cache = undefined;
|
||||
return p.byteLength;
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
if (this.cache) {
|
||||
return this.cache;
|
||||
}
|
||||
const buf = new Uint8Array(this.byteLength);
|
||||
let offs = 0;
|
||||
for (const chunk of this.chunks) {
|
||||
buf.set(chunk, offs);
|
||||
offs += chunk.byteLength;
|
||||
}
|
||||
this.cache = decode(buf);
|
||||
return this.cache;
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
// Loaded from https://deno.land/x/ramda@v0.27.2/source/drop.js
|
||||
|
||||
|
||||
import _curry2 from './internal/_curry2.js';
|
||||
import _dispatchable from './internal/_dispatchable.js';
|
||||
import _xdrop from './internal/_xdrop.js';
|
||||
import slice from './slice.js';
|
||||
|
||||
|
||||
/**
|
||||
* Returns all but the first `n` elements of the given list, string, or
|
||||
* transducer/transformer (or object with a `drop` method).
|
||||
*
|
||||
* Dispatches to the `drop` method of the second argument, if present.
|
||||
*
|
||||
* @func
|
||||
* @memberOf R
|
||||
* @since v0.1.0
|
||||
* @category List
|
||||
* @sig Number -> [a] -> [a]
|
||||
* @sig Number -> String -> String
|
||||
* @param {Number} n
|
||||
* @param {*} list
|
||||
* @return {*} A copy of list without the first `n` elements
|
||||
* @see R.take, R.transduce, R.dropLast, R.dropWhile
|
||||
* @example
|
||||
*
|
||||
* R.drop(1, ['foo', 'bar', 'baz']); //=> ['bar', 'baz']
|
||||
* R.drop(2, ['foo', 'bar', 'baz']); //=> ['baz']
|
||||
* R.drop(3, ['foo', 'bar', 'baz']); //=> []
|
||||
* R.drop(4, ['foo', 'bar', 'baz']); //=> []
|
||||
* R.drop(3, 'ramda'); //=> 'da'
|
||||
*/
|
||||
var drop = _curry2(_dispatchable(['drop'], _xdrop, function drop(n, xs) {
|
||||
return slice(Math.max(0, n), Infinity, xs);
|
||||
}));
|
||||
export default drop;
|
@ -0,0 +1,6 @@
|
||||
// Loaded from https://deno.land/x/graphql_deno@v15.0.0/lib/jsutils/nodejsCustomInspectSymbol.js
|
||||
|
||||
|
||||
/* istanbul ignore next (See: https://github.com/graphql/graphql-js/issues/2317) */
|
||||
const nodejsCustomInspectSymbol = typeof Symbol === 'function' && typeof Symbol.for === 'function' ? Symbol.for('nodejs.util.inspect.custom') : undefined;
|
||||
export default nodejsCustomInspectSymbol;
|
@ -0,0 +1,33 @@
|
||||
// Loaded from https://deno.land/std@0.73.0/path/_interface.ts
|
||||
|
||||
|
||||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
/** This module is browser compatible. */
|
||||
|
||||
/**
|
||||
* A parsed path object generated by path.parse() or consumed by path.format().
|
||||
*/
|
||||
export interface ParsedPath {
|
||||
/**
|
||||
* The root of the path such as '/' or 'c:\'
|
||||
*/
|
||||
root: string;
|
||||
/**
|
||||
* The full directory path such as '/home/user/dir' or 'c:\path\dir'
|
||||
*/
|
||||
dir: string;
|
||||
/**
|
||||
* The file name including extension (if any) such as 'index.html'
|
||||
*/
|
||||
base: string;
|
||||
/**
|
||||
* The file extension (if any) such as '.html'
|
||||
*/
|
||||
ext: string;
|
||||
/**
|
||||
* The file name without extension (if any) such as 'index'
|
||||
*/
|
||||
name: string;
|
||||
}
|
||||
|
||||
export type FormatInputPathObject = Partial<ParsedPath>;
|
@ -0,0 +1,10 @@
|
||||
// Loaded from https://deno.land/std@0.79.0/path/separator.ts
|
||||
|
||||
|
||||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
/** This module is browser compatible. */
|
||||
|
||||
import { isWindows } from "../_util/os.ts";
|
||||
|
||||
export const SEP = isWindows ? "\\" : "/";
|
||||
export const SEP_PATTERN = isWindows ? /[\\/]+/ : /\/+/;
|
File diff suppressed because one or more lines are too long
@ -0,0 +1,29 @@
|
||||
// Loaded from https://deno.land/x/ramda@v0.27.2/source/internal/_xdropRepeatsWith.js
|
||||
|
||||
|
||||
import _curry2 from './_curry2.js';
|
||||
import _xfBase from './_xfBase.js';
|
||||
|
||||
|
||||
function XDropRepeatsWith(pred, xf) {
|
||||
this.xf = xf;
|
||||
this.pred = pred;
|
||||
this.lastValue = undefined;
|
||||
this.seenFirstValue = false;
|
||||
}
|
||||
|
||||
XDropRepeatsWith.prototype['@@transducer/init'] = _xfBase.init;
|
||||
XDropRepeatsWith.prototype['@@transducer/result'] = _xfBase.result;
|
||||
XDropRepeatsWith.prototype['@@transducer/step'] = function(result, input) {
|
||||
var sameAsLast = false;
|
||||
if (!this.seenFirstValue) {
|
||||
this.seenFirstValue = true;
|
||||
} else if (this.pred(this.lastValue, input)) {
|
||||
sameAsLast = true;
|
||||
}
|
||||
this.lastValue = input;
|
||||
return sameAsLast ? result : this.xf['@@transducer/step'](result, input);
|
||||
};
|
||||
|
||||
var _xdropRepeatsWith = _curry2(function _xdropRepeatsWith(pred, xf) { return new XDropRepeatsWith(pred, xf); });
|
||||
export default _xdropRepeatsWith;
|
@ -0,0 +1,721 @@
|
||||
// Loaded from https://deno.land/std@0.83.0/io/bufio.ts
|
||||
|
||||
|
||||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
// Based on https://github.com/golang/go/blob/891682/src/bufio/bufio.go
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
type Reader = Deno.Reader;
|
||||
type Writer = Deno.Writer;
|
||||
type WriterSync = Deno.WriterSync;
|
||||
import { copy } from "../bytes/mod.ts";
|
||||
import { assert } from "../_util/assert.ts";
|
||||
|
||||
const DEFAULT_BUF_SIZE = 4096;
|
||||
const MIN_BUF_SIZE = 16;
|
||||
const MAX_CONSECUTIVE_EMPTY_READS = 100;
|
||||
const CR = "\r".charCodeAt(0);
|
||||
const LF = "\n".charCodeAt(0);
|
||||
|
||||
export class BufferFullError extends Error {
|
||||
name = "BufferFullError";
|
||||
constructor(public partial: Uint8Array) {
|
||||
super("Buffer full");
|
||||
}
|
||||
}
|
||||
|
||||
export class PartialReadError extends Deno.errors.UnexpectedEof {
|
||||
name = "PartialReadError";
|
||||
partial?: Uint8Array;
|
||||
constructor() {
|
||||
super("Encountered UnexpectedEof, data only partially read");
|
||||
}
|
||||
}
|
||||
|
||||
/** Result type returned by of BufReader.readLine(). */
|
||||
export interface ReadLineResult {
|
||||
line: Uint8Array;
|
||||
more: boolean;
|
||||
}
|
||||
|
||||
/** BufReader implements buffering for a Reader object. */
|
||||
export class BufReader implements Reader {
|
||||
private buf!: Uint8Array;
|
||||
private rd!: Reader; // Reader provided by caller.
|
||||
private r = 0; // buf read position.
|
||||
private w = 0; // buf write position.
|
||||
private eof = false;
|
||||
// private lastByte: number;
|
||||
// private lastCharSize: number;
|
||||
|
||||
/** return new BufReader unless r is BufReader */
|
||||
static create(r: Reader, size: number = DEFAULT_BUF_SIZE): BufReader {
|
||||
return r instanceof BufReader ? r : new BufReader(r, size);
|
||||
}
|
||||
|
||||
constructor(rd: Reader, size: number = DEFAULT_BUF_SIZE) {
|
||||
if (size < MIN_BUF_SIZE) {
|
||||
size = MIN_BUF_SIZE;
|
||||
}
|
||||
this._reset(new Uint8Array(size), rd);
|
||||
}
|
||||
|
||||
/** Returns the size of the underlying buffer in bytes. */
|
||||
size(): number {
|
||||
return this.buf.byteLength;
|
||||
}
|
||||
|
||||
buffered(): number {
|
||||
return this.w - this.r;
|
||||
}
|
||||
|
||||
// Reads a new chunk into the buffer.
|
||||
private async _fill(): Promise<void> {
|
||||
// Slide existing data to beginning.
|
||||
if (this.r > 0) {
|
||||
this.buf.copyWithin(0, this.r, this.w);
|
||||
this.w -= this.r;
|
||||
this.r = 0;
|
||||
}
|
||||
|
||||
if (this.w >= this.buf.byteLength) {
|
||||
throw Error("bufio: tried to fill full buffer");
|
||||
}
|
||||
|
||||
// Read new data: try a limited number of times.
|
||||
for (let i = MAX_CONSECUTIVE_EMPTY_READS; i > 0; i--) {
|
||||
const rr = await this.rd.read(this.buf.subarray(this.w));
|
||||
if (rr === null) {
|
||||
this.eof = true;
|
||||
return;
|
||||
}
|
||||
assert(rr >= 0, "negative read");
|
||||
this.w += rr;
|
||||
if (rr > 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error(
|
||||
`No progress after ${MAX_CONSECUTIVE_EMPTY_READS} read() calls`,
|
||||
);
|
||||
}
|
||||
|
||||
/** Discards any buffered data, resets all state, and switches
|
||||
* the buffered reader to read from r.
|
||||
*/
|
||||
reset(r: Reader): void {
|
||||
this._reset(this.buf, r);
|
||||
}
|
||||
|
||||
private _reset(buf: Uint8Array, rd: Reader): void {
|
||||
this.buf = buf;
|
||||
this.rd = rd;
|
||||
this.eof = false;
|
||||
// this.lastByte = -1;
|
||||
// this.lastCharSize = -1;
|
||||
}
|
||||
|
||||
/** reads data into p.
|
||||
* It returns the number of bytes read into p.
|
||||
* The bytes are taken from at most one Read on the underlying Reader,
|
||||
* hence n may be less than len(p).
|
||||
* To read exactly len(p) bytes, use io.ReadFull(b, p).
|
||||
*/
|
||||
async read(p: Uint8Array): Promise<number | null> {
|
||||
let rr: number | null = p.byteLength;
|
||||
if (p.byteLength === 0) return rr;
|
||||
|
||||
if (this.r === this.w) {
|
||||
if (p.byteLength >= this.buf.byteLength) {
|
||||
// Large read, empty buffer.
|
||||
// Read directly into p to avoid copy.
|
||||
const rr = await this.rd.read(p);
|
||||
const nread = rr ?? 0;
|
||||
assert(nread >= 0, "negative read");
|
||||
// if (rr.nread > 0) {
|
||||
// this.lastByte = p[rr.nread - 1];
|
||||
// this.lastCharSize = -1;
|
||||
// }
|
||||
return rr;
|
||||
}
|
||||
|
||||
// One read.
|
||||
// Do not use this.fill, which will loop.
|
||||
this.r = 0;
|
||||
this.w = 0;
|
||||
rr = await this.rd.read(this.buf);
|
||||
if (rr === 0 || rr === null) return rr;
|
||||
assert(rr >= 0, "negative read");
|
||||
this.w += rr;
|
||||
}
|
||||
|
||||
// copy as much as we can
|
||||
const copied = copy(this.buf.subarray(this.r, this.w), p, 0);
|
||||
this.r += copied;
|
||||
// this.lastByte = this.buf[this.r - 1];
|
||||
// this.lastCharSize = -1;
|
||||
return copied;
|
||||
}
|
||||
|
||||
/** reads exactly `p.length` bytes into `p`.
|
||||
*
|
||||
* If successful, `p` is returned.
|
||||
*
|
||||
* If the end of the underlying stream has been reached, and there are no more
|
||||
* bytes available in the buffer, `readFull()` returns `null` instead.
|
||||
*
|
||||
* An error is thrown if some bytes could be read, but not enough to fill `p`
|
||||
* entirely before the underlying stream reported an error or EOF. Any error
|
||||
* thrown will have a `partial` property that indicates the slice of the
|
||||
* buffer that has been successfully filled with data.
|
||||
*
|
||||
* Ported from https://golang.org/pkg/io/#ReadFull
|
||||
*/
|
||||
async readFull(p: Uint8Array): Promise<Uint8Array | null> {
|
||||
let bytesRead = 0;
|
||||
while (bytesRead < p.length) {
|
||||
try {
|
||||
const rr = await this.read(p.subarray(bytesRead));
|
||||
if (rr === null) {
|
||||
if (bytesRead === 0) {
|
||||
return null;
|
||||
} else {
|
||||
throw new PartialReadError();
|
||||
}
|
||||
}
|
||||
bytesRead += rr;
|
||||
} catch (err) {
|
||||
err.partial = p.subarray(0, bytesRead);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/** Returns the next byte [0, 255] or `null`. */
|
||||
async readByte(): Promise<number | null> {
|
||||
while (this.r === this.w) {
|
||||
if (this.eof) return null;
|
||||
await this._fill(); // buffer is empty.
|
||||
}
|
||||
const c = this.buf[this.r];
|
||||
this.r++;
|
||||
// this.lastByte = c;
|
||||
return c;
|
||||
}
|
||||
|
||||
/** readString() reads until the first occurrence of delim in the input,
|
||||
* returning a string containing the data up to and including the delimiter.
|
||||
* If ReadString encounters an error before finding a delimiter,
|
||||
* it returns the data read before the error and the error itself
|
||||
* (often `null`).
|
||||
* ReadString returns err != nil if and only if the returned data does not end
|
||||
* in delim.
|
||||
* For simple uses, a Scanner may be more convenient.
|
||||
*/
|
||||
async readString(delim: string): Promise<string | null> {
|
||||
if (delim.length !== 1) {
|
||||
throw new Error("Delimiter should be a single character");
|
||||
}
|
||||
const buffer = await this.readSlice(delim.charCodeAt(0));
|
||||
if (buffer === null) return null;
|
||||
return new TextDecoder().decode(buffer);
|
||||
}
|
||||
|
||||
/** `readLine()` is a low-level line-reading primitive. Most callers should
|
||||
* use `readString('\n')` instead or use a Scanner.
|
||||
*
|
||||
* `readLine()` tries to return a single line, not including the end-of-line
|
||||
* bytes. If the line was too long for the buffer then `more` is set and the
|
||||
* beginning of the line is returned. The rest of the line will be returned
|
||||
* from future calls. `more` will be false when returning the last fragment
|
||||
* of the line. The returned buffer is only valid until the next call to
|
||||
* `readLine()`.
|
||||
*
|
||||
* The text returned from ReadLine does not include the line end ("\r\n" or
|
||||
* "\n").
|
||||
*
|
||||
* When the end of the underlying stream is reached, the final bytes in the
|
||||
* stream are returned. No indication or error is given if the input ends
|
||||
* without a final line end. When there are no more trailing bytes to read,
|
||||
* `readLine()` returns `null`.
|
||||
*
|
||||
* Calling `unreadByte()` after `readLine()` will always unread the last byte
|
||||
* read (possibly a character belonging to the line end) even if that byte is
|
||||
* not part of the line returned by `readLine()`.
|
||||
*/
|
||||
async readLine(): Promise<ReadLineResult | null> {
|
||||
let line: Uint8Array | null;
|
||||
|
||||
try {
|
||||
line = await this.readSlice(LF);
|
||||
} catch (err) {
|
||||
let { partial } = err;
|
||||
assert(
|
||||
partial instanceof Uint8Array,
|
||||
"bufio: caught error from `readSlice()` without `partial` property",
|
||||
);
|
||||
|
||||
// Don't throw if `readSlice()` failed with `BufferFullError`, instead we
|
||||
// just return whatever is available and set the `more` flag.
|
||||
if (!(err instanceof BufferFullError)) {
|
||||
throw err;
|
||||
}
|
||||
|
||||
// Handle the case where "\r\n" straddles the buffer.
|
||||
if (
|
||||
!this.eof &&
|
||||
partial.byteLength > 0 &&
|
||||
partial[partial.byteLength - 1] === CR
|
||||
) {
|
||||
// Put the '\r' back on buf and drop it from line.
|
||||
// Let the next call to ReadLine check for "\r\n".
|
||||
assert(this.r > 0, "bufio: tried to rewind past start of buffer");
|
||||
this.r--;
|
||||
partial = partial.subarray(0, partial.byteLength - 1);
|
||||
}
|
||||
|
||||
return { line: partial, more: !this.eof };
|
||||
}
|
||||
|
||||
if (line === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (line.byteLength === 0) {
|
||||
return { line, more: false };
|
||||
}
|
||||
|
||||
if (line[line.byteLength - 1] == LF) {
|
||||
let drop = 1;
|
||||
if (line.byteLength > 1 && line[line.byteLength - 2] === CR) {
|
||||
drop = 2;
|
||||
}
|
||||
line = line.subarray(0, line.byteLength - drop);
|
||||
}
|
||||
return { line, more: false };
|
||||
}
|
||||
|
||||
/** `readSlice()` reads until the first occurrence of `delim` in the input,
|
||||
* returning a slice pointing at the bytes in the buffer. The bytes stop
|
||||
* being valid at the next read.
|
||||
*
|
||||
* If `readSlice()` encounters an error before finding a delimiter, or the
|
||||
* buffer fills without finding a delimiter, it throws an error with a
|
||||
* `partial` property that contains the entire buffer.
|
||||
*
|
||||
* If `readSlice()` encounters the end of the underlying stream and there are
|
||||
* any bytes left in the buffer, the rest of the buffer is returned. In other
|
||||
* words, EOF is always treated as a delimiter. Once the buffer is empty,
|
||||
* it returns `null`.
|
||||
*
|
||||
* Because the data returned from `readSlice()` will be overwritten by the
|
||||
* next I/O operation, most clients should use `readString()` instead.
|
||||
*/
|
||||
async readSlice(delim: number): Promise<Uint8Array | null> {
|
||||
let s = 0; // search start index
|
||||
let slice: Uint8Array | undefined;
|
||||
|
||||
while (true) {
|
||||
// Search buffer.
|
||||
let i = this.buf.subarray(this.r + s, this.w).indexOf(delim);
|
||||
if (i >= 0) {
|
||||
i += s;
|
||||
slice = this.buf.subarray(this.r, this.r + i + 1);
|
||||
this.r += i + 1;
|
||||
break;
|
||||
}
|
||||
|
||||
// EOF?
|
||||
if (this.eof) {
|
||||
if (this.r === this.w) {
|
||||
return null;
|
||||
}
|
||||
slice = this.buf.subarray(this.r, this.w);
|
||||
this.r = this.w;
|
||||
break;
|
||||
}
|
||||
|
||||
// Buffer full?
|
||||
if (this.buffered() >= this.buf.byteLength) {
|
||||
this.r = this.w;
|
||||
// #4521 The internal buffer should not be reused across reads because it causes corruption of data.
|
||||
const oldbuf = this.buf;
|
||||
const newbuf = this.buf.slice(0);
|
||||
this.buf = newbuf;
|
||||
throw new BufferFullError(oldbuf);
|
||||
}
|
||||
|
||||
s = this.w - this.r; // do not rescan area we scanned before
|
||||
|
||||
// Buffer is not full.
|
||||
try {
|
||||
await this._fill();
|
||||
} catch (err) {
|
||||
err.partial = slice;
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle last byte, if any.
|
||||
// const i = slice.byteLength - 1;
|
||||
// if (i >= 0) {
|
||||
// this.lastByte = slice[i];
|
||||
// this.lastCharSize = -1
|
||||
// }
|
||||
|
||||
return slice;
|
||||
}
|
||||
|
||||
/** `peek()` returns the next `n` bytes without advancing the reader. The
|
||||
* bytes stop being valid at the next read call.
|
||||
*
|
||||
* When the end of the underlying stream is reached, but there are unread
|
||||
* bytes left in the buffer, those bytes are returned. If there are no bytes
|
||||
* left in the buffer, it returns `null`.
|
||||
*
|
||||
* If an error is encountered before `n` bytes are available, `peek()` throws
|
||||
* an error with the `partial` property set to a slice of the buffer that
|
||||
* contains the bytes that were available before the error occurred.
|
||||
*/
|
||||
async peek(n: number): Promise<Uint8Array | null> {
|
||||
if (n < 0) {
|
||||
throw Error("negative count");
|
||||
}
|
||||
|
||||
let avail = this.w - this.r;
|
||||
while (avail < n && avail < this.buf.byteLength && !this.eof) {
|
||||
try {
|
||||
await this._fill();
|
||||
} catch (err) {
|
||||
err.partial = this.buf.subarray(this.r, this.w);
|
||||
throw err;
|
||||
}
|
||||
avail = this.w - this.r;
|
||||
}
|
||||
|
||||
if (avail === 0 && this.eof) {
|
||||
return null;
|
||||
} else if (avail < n && this.eof) {
|
||||
return this.buf.subarray(this.r, this.r + avail);
|
||||
} else if (avail < n) {
|
||||
throw new BufferFullError(this.buf.subarray(this.r, this.w));
|
||||
}
|
||||
|
||||
return this.buf.subarray(this.r, this.r + n);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class AbstractBufBase {
|
||||
buf!: Uint8Array;
|
||||
usedBufferBytes = 0;
|
||||
err: Error | null = null;
|
||||
|
||||
/** Size returns the size of the underlying buffer in bytes. */
|
||||
size(): number {
|
||||
return this.buf.byteLength;
|
||||
}
|
||||
|
||||
/** Returns how many bytes are unused in the buffer. */
|
||||
available(): number {
|
||||
return this.buf.byteLength - this.usedBufferBytes;
|
||||
}
|
||||
|
||||
/** buffered returns the number of bytes that have been written into the
|
||||
* current buffer.
|
||||
*/
|
||||
buffered(): number {
|
||||
return this.usedBufferBytes;
|
||||
}
|
||||
}
|
||||
|
||||
/** BufWriter implements buffering for an deno.Writer object.
|
||||
* If an error occurs writing to a Writer, no more data will be
|
||||
* accepted and all subsequent writes, and flush(), will return the error.
|
||||
* After all data has been written, the client should call the
|
||||
* flush() method to guarantee all data has been forwarded to
|
||||
* the underlying deno.Writer.
|
||||
*/
|
||||
export class BufWriter extends AbstractBufBase implements Writer {
|
||||
/** return new BufWriter unless writer is BufWriter */
|
||||
static create(writer: Writer, size: number = DEFAULT_BUF_SIZE): BufWriter {
|
||||
return writer instanceof BufWriter ? writer : new BufWriter(writer, size);
|
||||
}
|
||||
|
||||
constructor(private writer: Writer, size: number = DEFAULT_BUF_SIZE) {
|
||||
super();
|
||||
if (size <= 0) {
|
||||
size = DEFAULT_BUF_SIZE;
|
||||
}
|
||||
this.buf = new Uint8Array(size);
|
||||
}
|
||||
|
||||
/** Discards any unflushed buffered data, clears any error, and
|
||||
* resets buffer to write its output to w.
|
||||
*/
|
||||
reset(w: Writer): void {
|
||||
this.err = null;
|
||||
this.usedBufferBytes = 0;
|
||||
this.writer = w;
|
||||
}
|
||||
|
||||
/** Flush writes any buffered data to the underlying io.Writer. */
|
||||
async flush(): Promise<void> {
|
||||
if (this.err !== null) throw this.err;
|
||||
if (this.usedBufferBytes === 0) return;
|
||||
|
||||
try {
|
||||
await Deno.writeAll(
|
||||
this.writer,
|
||||
this.buf.subarray(0, this.usedBufferBytes),
|
||||
);
|
||||
} catch (e) {
|
||||
this.err = e;
|
||||
throw e;
|
||||
}
|
||||
|
||||
this.buf = new Uint8Array(this.buf.length);
|
||||
this.usedBufferBytes = 0;
|
||||
}
|
||||
|
||||
/** Writes the contents of `data` into the buffer. If the contents won't fully
|
||||
* fit into the buffer, those bytes that can are copied into the buffer, the
|
||||
* buffer is the flushed to the writer and the remaining bytes are copied into
|
||||
* the now empty buffer.
|
||||
*
|
||||
* @return the number of bytes written to the buffer.
|
||||
*/
|
||||
async write(data: Uint8Array): Promise<number> {
|
||||
if (this.err !== null) throw this.err;
|
||||
if (data.length === 0) return 0;
|
||||
|
||||
let totalBytesWritten = 0;
|
||||
let numBytesWritten = 0;
|
||||
while (data.byteLength > this.available()) {
|
||||
if (this.buffered() === 0) {
|
||||
// Large write, empty buffer.
|
||||
// Write directly from data to avoid copy.
|
||||
try {
|
||||
numBytesWritten = await this.writer.write(data);
|
||||
} catch (e) {
|
||||
this.err = e;
|
||||
throw e;
|
||||
}
|
||||
} else {
|
||||
numBytesWritten = copy(data, this.buf, this.usedBufferBytes);
|
||||
this.usedBufferBytes += numBytesWritten;
|
||||
await this.flush();
|
||||
}
|
||||
totalBytesWritten += numBytesWritten;
|
||||
data = data.subarray(numBytesWritten);
|
||||
}
|
||||
|
||||
numBytesWritten = copy(data, this.buf, this.usedBufferBytes);
|
||||
this.usedBufferBytes += numBytesWritten;
|
||||
totalBytesWritten += numBytesWritten;
|
||||
return totalBytesWritten;
|
||||
}
|
||||
}
|
||||
|
||||
/** BufWriterSync implements buffering for a deno.WriterSync object.
|
||||
* If an error occurs writing to a WriterSync, no more data will be
|
||||
* accepted and all subsequent writes, and flush(), will return the error.
|
||||
* After all data has been written, the client should call the
|
||||
* flush() method to guarantee all data has been forwarded to
|
||||
* the underlying deno.WriterSync.
|
||||
*/
|
||||
export class BufWriterSync extends AbstractBufBase implements WriterSync {
|
||||
/** return new BufWriterSync unless writer is BufWriterSync */
|
||||
static create(
|
||||
writer: WriterSync,
|
||||
size: number = DEFAULT_BUF_SIZE,
|
||||
): BufWriterSync {
|
||||
return writer instanceof BufWriterSync
|
||||
? writer
|
||||
: new BufWriterSync(writer, size);
|
||||
}
|
||||
|
||||
constructor(private writer: WriterSync, size: number = DEFAULT_BUF_SIZE) {
|
||||
super();
|
||||
if (size <= 0) {
|
||||
size = DEFAULT_BUF_SIZE;
|
||||
}
|
||||
this.buf = new Uint8Array(size);
|
||||
}
|
||||
|
||||
/** Discards any unflushed buffered data, clears any error, and
|
||||
* resets buffer to write its output to w.
|
||||
*/
|
||||
reset(w: WriterSync): void {
|
||||
this.err = null;
|
||||
this.usedBufferBytes = 0;
|
||||
this.writer = w;
|
||||
}
|
||||
|
||||
/** Flush writes any buffered data to the underlying io.WriterSync. */
|
||||
flush(): void {
|
||||
if (this.err !== null) throw this.err;
|
||||
if (this.usedBufferBytes === 0) return;
|
||||
|
||||
try {
|
||||
Deno.writeAllSync(
|
||||
this.writer,
|
||||
this.buf.subarray(0, this.usedBufferBytes),
|
||||
);
|
||||
} catch (e) {
|
||||
this.err = e;
|
||||
throw e;
|
||||
}
|
||||
|
||||
this.buf = new Uint8Array(this.buf.length);
|
||||
this.usedBufferBytes = 0;
|
||||
}
|
||||
|
||||
/** Writes the contents of `data` into the buffer. If the contents won't fully
|
||||
* fit into the buffer, those bytes that can are copied into the buffer, the
|
||||
* buffer is the flushed to the writer and the remaining bytes are copied into
|
||||
* the now empty buffer.
|
||||
*
|
||||
* @return the number of bytes written to the buffer.
|
||||
*/
|
||||
writeSync(data: Uint8Array): number {
|
||||
if (this.err !== null) throw this.err;
|
||||
if (data.length === 0) return 0;
|
||||
|
||||
let totalBytesWritten = 0;
|
||||
let numBytesWritten = 0;
|
||||
while (data.byteLength > this.available()) {
|
||||
if (this.buffered() === 0) {
|
||||
// Large write, empty buffer.
|
||||
// Write directly from data to avoid copy.
|
||||
try {
|
||||
numBytesWritten = this.writer.writeSync(data);
|
||||
} catch (e) {
|
||||
this.err = e;
|
||||
throw e;
|
||||
}
|
||||
} else {
|
||||
numBytesWritten = copy(data, this.buf, this.usedBufferBytes);
|
||||
this.usedBufferBytes += numBytesWritten;
|
||||
this.flush();
|
||||
}
|
||||
totalBytesWritten += numBytesWritten;
|
||||
data = data.subarray(numBytesWritten);
|
||||
}
|
||||
|
||||
numBytesWritten = copy(data, this.buf, this.usedBufferBytes);
|
||||
this.usedBufferBytes += numBytesWritten;
|
||||
totalBytesWritten += numBytesWritten;
|
||||
return totalBytesWritten;
|
||||
}
|
||||
}
|
||||
|
||||
/** Generate longest proper prefix which is also suffix array. */
|
||||
function createLPS(pat: Uint8Array): Uint8Array {
|
||||
const lps = new Uint8Array(pat.length);
|
||||
lps[0] = 0;
|
||||
let prefixEnd = 0;
|
||||
let i = 1;
|
||||
while (i < lps.length) {
|
||||
if (pat[i] == pat[prefixEnd]) {
|
||||
prefixEnd++;
|
||||
lps[i] = prefixEnd;
|
||||
i++;
|
||||
} else if (prefixEnd === 0) {
|
||||
lps[i] = 0;
|
||||
i++;
|
||||
} else {
|
||||
prefixEnd = pat[prefixEnd - 1];
|
||||
}
|
||||
}
|
||||
return lps;
|
||||
}
|
||||
|
||||
/** Read delimited bytes from a Reader. */
|
||||
export async function* readDelim(
|
||||
reader: Reader,
|
||||
delim: Uint8Array,
|
||||
): AsyncIterableIterator<Uint8Array> {
|
||||
// Avoid unicode problems
|
||||
const delimLen = delim.length;
|
||||
const delimLPS = createLPS(delim);
|
||||
|
||||
let inputBuffer = new Deno.Buffer();
|
||||
const inspectArr = new Uint8Array(Math.max(1024, delimLen + 1));
|
||||
|
||||
// Modified KMP
|
||||
let inspectIndex = 0;
|
||||
let matchIndex = 0;
|
||||
while (true) {
|
||||
const result = await reader.read(inspectArr);
|
||||
if (result === null) {
|
||||
// Yield last chunk.
|
||||
yield inputBuffer.bytes();
|
||||
return;
|
||||
}
|
||||
if ((result as number) < 0) {
|
||||
// Discard all remaining and silently fail.
|
||||
return;
|
||||
}
|
||||
const sliceRead = inspectArr.subarray(0, result as number);
|
||||
await Deno.writeAll(inputBuffer, sliceRead);
|
||||
|
||||
let sliceToProcess = inputBuffer.bytes();
|
||||
while (inspectIndex < sliceToProcess.length) {
|
||||
if (sliceToProcess[inspectIndex] === delim[matchIndex]) {
|
||||
inspectIndex++;
|
||||
matchIndex++;
|
||||
if (matchIndex === delimLen) {
|
||||
// Full match
|
||||
const matchEnd = inspectIndex - delimLen;
|
||||
const readyBytes = sliceToProcess.subarray(0, matchEnd);
|
||||
// Copy
|
||||
const pendingBytes = sliceToProcess.slice(inspectIndex);
|
||||
yield readyBytes;
|
||||
// Reset match, different from KMP.
|
||||
sliceToProcess = pendingBytes;
|
||||
inspectIndex = 0;
|
||||
matchIndex = 0;
|
||||
}
|
||||
} else {
|
||||
if (matchIndex === 0) {
|
||||
inspectIndex++;
|
||||
} else {
|
||||
matchIndex = delimLPS[matchIndex - 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
// Keep inspectIndex and matchIndex.
|
||||
inputBuffer = new Deno.Buffer(sliceToProcess);
|
||||
}
|
||||
}
|
||||
|
||||
/** Read delimited strings from a Reader. */
|
||||
export async function* readStringDelim(
|
||||
reader: Reader,
|
||||
delim: string,
|
||||
): AsyncIterableIterator<string> {
|
||||
const encoder = new TextEncoder();
|
||||
const decoder = new TextDecoder();
|
||||
for await (const chunk of readDelim(reader, encoder.encode(delim))) {
|
||||
yield decoder.decode(chunk);
|
||||
}
|
||||
}
|
||||
|
||||
/** Read strings line-by-line from a Reader. */
|
||||
export async function* readLines(
|
||||
reader: Reader,
|
||||
): AsyncIterableIterator<string> {
|
||||
for await (let chunk of readStringDelim(reader, "\n")) {
|
||||
// Finding a CR at the end of the line is evidence of a
|
||||
// "\r\n" at the end of the line. The "\r" part should be
|
||||
// removed too.
|
||||
if (chunk.endsWith("\r")) {
|
||||
chunk = chunk.slice(0, -1);
|
||||
}
|
||||
yield chunk;
|
||||
}
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
// Loaded from https://deno.land/x/mysql/src/packets/builders/auth.ts
|
||||
|
||||
|
||||
import auth from "../../auth.ts";
|
||||
import { BufferWriter } from "../../buffer.ts";
|
||||
import ServerCapabilities from "../../constant/capabilities.ts";
|
||||
import { Charset } from "../../constant/charset.ts";
|
||||
import type { HandshakeBody } from "../parsers/handshake.ts";
|
||||
|
||||
/** @ignore */
|
||||
export function buildAuth(
|
||||
packet: HandshakeBody,
|
||||
params: { username: string; password?: string; db?: string },
|
||||
): Uint8Array {
|
||||
const clientParam: number =
|
||||
(params.db ? ServerCapabilities.CLIENT_CONNECT_WITH_DB : 0) |
|
||||
ServerCapabilities.CLIENT_PLUGIN_AUTH |
|
||||
ServerCapabilities.CLIENT_LONG_PASSWORD |
|
||||
ServerCapabilities.CLIENT_PROTOCOL_41 |
|
||||
ServerCapabilities.CLIENT_TRANSACTIONS |
|
||||
ServerCapabilities.CLIENT_MULTI_RESULTS |
|
||||
ServerCapabilities.CLIENT_SECURE_CONNECTION |
|
||||
(ServerCapabilities.CLIENT_LONG_FLAG & packet.serverCapabilities) |
|
||||
(ServerCapabilities.CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA &
|
||||
packet.serverCapabilities) |
|
||||
(ServerCapabilities.CLIENT_DEPRECATE_EOF & packet.serverCapabilities);
|
||||
|
||||
if (packet.serverCapabilities & ServerCapabilities.CLIENT_PLUGIN_AUTH) {
|
||||
const writer = new BufferWriter(new Uint8Array(1000));
|
||||
writer
|
||||
.writeUint32(clientParam)
|
||||
.writeUint32(2 ** 24 - 1)
|
||||
.write(Charset.UTF8_GENERAL_CI)
|
||||
.skip(23)
|
||||
.writeNullTerminatedString(params.username);
|
||||
if (params.password) {
|
||||
const authData = auth(
|
||||
packet.authPluginName,
|
||||
params.password,
|
||||
packet.seed,
|
||||
);
|
||||
if (
|
||||
clientParam &
|
||||
ServerCapabilities.CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA ||
|
||||
clientParam & ServerCapabilities.CLIENT_SECURE_CONNECTION
|
||||
) {
|
||||
// request lenenc-int length of auth-response and string[n] auth-response
|
||||
writer.write(authData.length);
|
||||
writer.writeBuffer(authData);
|
||||
} else {
|
||||
writer.writeBuffer(authData);
|
||||
writer.write(0);
|
||||
}
|
||||
} else {
|
||||
writer.write(0);
|
||||
}
|
||||
if (clientParam & ServerCapabilities.CLIENT_CONNECT_WITH_DB && params.db) {
|
||||
writer.writeNullTerminatedString(params.db);
|
||||
}
|
||||
if (clientParam & ServerCapabilities.CLIENT_PLUGIN_AUTH) {
|
||||
writer.writeNullTerminatedString(packet.authPluginName);
|
||||
}
|
||||
return writer.wroteData;
|
||||
}
|
||||
return Uint8Array.from([]);
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
// Loaded from https://deno.land/x/segno@v1.1.0/lib/validations/isDate.ts
|
||||
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
const isValidFormat = (format: string) => {
|
||||
return /(^(y{4}|y{2})[\/-](m{1,2})[\/-](d{1,2})$)|(^(m{1,2})[\/-](d{1,2})[\/-]((y{4}|y{2})$))|(^(d{1,2})[\/-](m{1,2})[\/-]((y{4}|y{2})$))/gi.test(
|
||||
format
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
const zip = (date: string[], format: string[]) => {
|
||||
const zippedArr = [];
|
||||
const len = Math.min(date.length, format.length);
|
||||
|
||||
for (let i = 0; i < len; i++) {
|
||||
zippedArr.push([date[i], format[i]]);
|
||||
}
|
||||
|
||||
return zippedArr;
|
||||
};
|
||||
|
||||
export const isDate = (input: any, format = 'YYYY/MM/DD') => {
|
||||
if (typeof input === 'string' && isValidFormat(format)) {
|
||||
const splitter = /[-/]/;
|
||||
const dateAndFormat = zip(
|
||||
input.split(splitter),
|
||||
format.toLowerCase().split(splitter)
|
||||
);
|
||||
const dateObj = {} as any;
|
||||
|
||||
for (const [dateWord, formatWord] of dateAndFormat) {
|
||||
if (dateWord.length !== formatWord.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
dateObj[formatWord.charAt(0)] = dateWord;
|
||||
}
|
||||
|
||||
return (
|
||||
new Date(`${dateObj.m}/${dateObj.d}/${dateObj.y}`).getDate() ===
|
||||
+dateObj.d
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
Object.prototype.toString.call(input) === '[object Date]' && isFinite(input)
|
||||
);
|
||||
};
|
@ -0,0 +1,123 @@
|
||||
// Loaded from https://deno.land/x/segno@v1.1.0/lib/validations/isCurrency.ts
|
||||
|
||||
|
||||
// @ts-ignore allowing typedoc to build
|
||||
import { assertString } from '../helpers/assertString.ts';
|
||||
|
||||
type CurrencyOptions = {
|
||||
symbol?: string;
|
||||
requireSymbol?: boolean;
|
||||
allowSpaceAfterSymbol?: boolean;
|
||||
symbolAfterDigits?: boolean;
|
||||
allowNegatives?: boolean;
|
||||
parensForNegatives?: boolean;
|
||||
negativeSignBeforeDigits?: boolean;
|
||||
negativeSignAfterDigits?: boolean;
|
||||
allowNegativeSignPlaceholder?: boolean;
|
||||
thousandsSeparator?: string;
|
||||
decimalSeparator?: string;
|
||||
allowDecimal?: boolean;
|
||||
requireDecimal?: boolean;
|
||||
digitsAfterDecimal?: number[];
|
||||
allowSpaceAfterDigits?: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
const currencyRegex = (options: Required<CurrencyOptions>) => {
|
||||
let decimalDigits = `\\d{${options.digitsAfterDecimal[0]}}`;
|
||||
options.digitsAfterDecimal.forEach((digit, index) => {
|
||||
if (index !== 0) decimalDigits = `${decimalDigits}|\\d{${digit}}`;
|
||||
});
|
||||
|
||||
const symbol = `(${options.symbol.replace(/\W/, (m) => `\\${m}`)})${
|
||||
options.requireSymbol ? '' : '?'
|
||||
}`,
|
||||
negative = '-?',
|
||||
whole_dollar_amount_without_sep = '[1-9]\\d*',
|
||||
whole_dollar_amount_with_sep = `[1-9]\\d{0,2}(\\${options.thousandsSeparator}\\d{3})*`,
|
||||
valid_whole_dollar_amounts = [
|
||||
'0',
|
||||
whole_dollar_amount_without_sep,
|
||||
whole_dollar_amount_with_sep,
|
||||
],
|
||||
whole_dollar_amount = `(${valid_whole_dollar_amounts.join('|')})?`,
|
||||
decimal_amount = `(\\${options.decimalSeparator}(${decimalDigits}))${
|
||||
options.requireDecimal ? '' : '?'
|
||||
}`;
|
||||
|
||||
let pattern =
|
||||
whole_dollar_amount +
|
||||
(options.allowDecimal || options.requireDecimal ? decimal_amount : '');
|
||||
|
||||
// default is negative sign before symbol, but there are two other options (besides parens)
|
||||
if (options.allowNegatives && !options.parensForNegatives) {
|
||||
if (options.negativeSignAfterDigits) {
|
||||
pattern += negative;
|
||||
} else if (options.negativeSignBeforeDigits) {
|
||||
pattern = negative + pattern;
|
||||
}
|
||||
}
|
||||
|
||||
// South African Rand, for example, uses R 123 (space) and R-123 (no space)
|
||||
if (options.allowNegativeSignPlaceholder) {
|
||||
pattern = `( (?!\\-))?${pattern}`;
|
||||
} else if (options.allowSpaceAfterSymbol) {
|
||||
pattern = ` ?${pattern}`;
|
||||
} else if (options.allowSpaceAfterDigits) {
|
||||
pattern += '( (?!$))?';
|
||||
}
|
||||
|
||||
if (options.symbolAfterDigits) {
|
||||
pattern += symbol;
|
||||
} else {
|
||||
pattern = symbol + pattern;
|
||||
}
|
||||
|
||||
if (options.allowNegatives) {
|
||||
if (options.parensForNegatives) {
|
||||
pattern = `(\\(${pattern}\\)|${pattern})`;
|
||||
} else if (
|
||||
!(options.negativeSignBeforeDigits || options.negativeSignAfterDigits)
|
||||
) {
|
||||
pattern = negative + pattern;
|
||||
}
|
||||
}
|
||||
|
||||
// ensure there's a dollar and/or decimal amount, and that
|
||||
// it doesn't start with a space or a negative sign followed by a space
|
||||
return new RegExp(`^(?!-? )(?=.*\\d)${pattern}$`);
|
||||
};
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
const defaultCurrencyOptions: CurrencyOptions = {
|
||||
symbol: '$',
|
||||
requireSymbol: false,
|
||||
allowSpaceAfterSymbol: false,
|
||||
symbolAfterDigits: false,
|
||||
allowNegatives: true,
|
||||
parensForNegatives: false,
|
||||
negativeSignBeforeDigits: false,
|
||||
negativeSignAfterDigits: false,
|
||||
allowNegativeSignPlaceholder: false,
|
||||
thousandsSeparator: ',',
|
||||
decimalSeparator: '.',
|
||||
allowDecimal: true,
|
||||
requireDecimal: false,
|
||||
digitsAfterDecimal: [2],
|
||||
allowSpaceAfterDigits: false,
|
||||
};
|
||||
|
||||
export const isCurrency = (str: string, options?: CurrencyOptions) => {
|
||||
assertString(str);
|
||||
|
||||
options = {
|
||||
...defaultCurrencyOptions,
|
||||
...options,
|
||||
};
|
||||
|
||||
return currencyRegex(options as Required<CurrencyOptions>).test(str);
|
||||
};
|
@ -0,0 +1,207 @@
|
||||
// Loaded from https://deno.land/std@0.81.0/http/cookie.ts
|
||||
|
||||
|
||||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
// Structured similarly to Go's cookie.go
|
||||
// https://github.com/golang/go/blob/master/src/net/http/cookie.go
|
||||
import { assert } from "../_util/assert.ts";
|
||||
import { toIMF } from "../datetime/mod.ts";
|
||||
|
||||
export type Cookies = Record<string, string>;
|
||||
|
||||
export interface Cookie {
|
||||
/** Name of the cookie. */
|
||||
name: string;
|
||||
/** Value of the cookie. */
|
||||
value: string;
|
||||
/** Expiration date of the cookie. */
|
||||
expires?: Date;
|
||||
/** Max-Age of the Cookie. Must be integer superior to 0. */
|
||||
maxAge?: number;
|
||||
/** Specifies those hosts to which the cookie will be sent. */
|
||||
domain?: string;
|
||||
/** Indicates a URL path that must exist in the request. */
|
||||
path?: string;
|
||||
/** Indicates if the cookie is made using SSL & HTTPS. */
|
||||
secure?: boolean;
|
||||
/** Indicates that cookie is not accessible via JavaScript. **/
|
||||
httpOnly?: boolean;
|
||||
/** Allows servers to assert that a cookie ought not to
|
||||
* be sent along with cross-site requests. */
|
||||
sameSite?: SameSite;
|
||||
/** Additional key value pairs with the form "key=value" */
|
||||
unparsed?: string[];
|
||||
}
|
||||
|
||||
export type SameSite = "Strict" | "Lax" | "None";
|
||||
|
||||
const FIELD_CONTENT_REGEXP = /^(?=[\x20-\x7E]*$)[^()@<>,;:\\"\[\]?={}\s]+$/;
|
||||
|
||||
function toString(cookie: Cookie): string {
|
||||
if (!cookie.name) {
|
||||
return "";
|
||||
}
|
||||
const out: string[] = [];
|
||||
validateCookieName(cookie.name);
|
||||
validateCookieValue(cookie.name, cookie.value);
|
||||
out.push(`${cookie.name}=${cookie.value}`);
|
||||
|
||||
// Fallback for invalid Set-Cookie
|
||||
// ref: https://tools.ietf.org/html/draft-ietf-httpbis-cookie-prefixes-00#section-3.1
|
||||
if (cookie.name.startsWith("__Secure")) {
|
||||
cookie.secure = true;
|
||||
}
|
||||
if (cookie.name.startsWith("__Host")) {
|
||||
cookie.path = "/";
|
||||
cookie.secure = true;
|
||||
delete cookie.domain;
|
||||
}
|
||||
|
||||
if (cookie.secure) {
|
||||
out.push("Secure");
|
||||
}
|
||||
if (cookie.httpOnly) {
|
||||
out.push("HttpOnly");
|
||||
}
|
||||
if (typeof cookie.maxAge === "number" && Number.isInteger(cookie.maxAge)) {
|
||||
assert(cookie.maxAge > 0, "Max-Age must be an integer superior to 0");
|
||||
out.push(`Max-Age=${cookie.maxAge}`);
|
||||
}
|
||||
if (cookie.domain) {
|
||||
out.push(`Domain=${cookie.domain}`);
|
||||
}
|
||||
if (cookie.sameSite) {
|
||||
out.push(`SameSite=${cookie.sameSite}`);
|
||||
}
|
||||
if (cookie.path) {
|
||||
validatePath(cookie.path);
|
||||
out.push(`Path=${cookie.path}`);
|
||||
}
|
||||
if (cookie.expires) {
|
||||
const dateString = toIMF(cookie.expires);
|
||||
out.push(`Expires=${dateString}`);
|
||||
}
|
||||
if (cookie.unparsed) {
|
||||
out.push(cookie.unparsed.join("; "));
|
||||
}
|
||||
return out.join("; ");
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate Cookie Name.
|
||||
* @param name Cookie name.
|
||||
*/
|
||||
function validateCookieName(name: string | undefined | null): void {
|
||||
if (name && !FIELD_CONTENT_REGEXP.test(name)) {
|
||||
throw new TypeError(`Invalid cookie name: "${name}".`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate Path Value.
|
||||
* @see https://tools.ietf.org/html/rfc6265#section-4.1.2.4
|
||||
* @param path Path value.
|
||||
*/
|
||||
function validatePath(path: string | null): void {
|
||||
if (path == null) {
|
||||
return;
|
||||
}
|
||||
for (let i = 0; i < path.length; i++) {
|
||||
const c = path.charAt(i);
|
||||
if (
|
||||
c < String.fromCharCode(0x20) || c > String.fromCharCode(0x7E) || c == ";"
|
||||
) {
|
||||
throw new Error(
|
||||
path + ": Invalid cookie path char '" + c + "'",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*Validate Cookie Value.
|
||||
* @see https://tools.ietf.org/html/rfc6265#section-4.1
|
||||
* @param value Cookie value.
|
||||
*/
|
||||
function validateCookieValue(name: string, value: string | null): void {
|
||||
if (value == null || name == null) return;
|
||||
for (let i = 0; i < value.length; i++) {
|
||||
const c = value.charAt(i);
|
||||
if (
|
||||
c < String.fromCharCode(0x21) || c == String.fromCharCode(0x22) ||
|
||||
c == String.fromCharCode(0x2c) || c == String.fromCharCode(0x3b) ||
|
||||
c == String.fromCharCode(0x5c) || c == String.fromCharCode(0x7f)
|
||||
) {
|
||||
throw new Error(
|
||||
"RFC2616 cookie '" + name + "' cannot have '" + c + "' as value",
|
||||
);
|
||||
}
|
||||
if (c > String.fromCharCode(0x80)) {
|
||||
throw new Error(
|
||||
"RFC2616 cookie '" + name + "' can only have US-ASCII chars as value" +
|
||||
c.charCodeAt(0).toString(16),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the cookies of the Server Request
|
||||
* @param req An object which has a `headers` property
|
||||
*/
|
||||
export function getCookies(req: { headers: Headers }): Cookies {
|
||||
const cookie = req.headers.get("Cookie");
|
||||
if (cookie != null) {
|
||||
const out: Cookies = {};
|
||||
const c = cookie.split(";");
|
||||
for (const kv of c) {
|
||||
const [cookieKey, ...cookieVal] = kv.split("=");
|
||||
assert(cookieKey != null);
|
||||
const key = cookieKey.trim();
|
||||
out[key] = cookieVal.join("=");
|
||||
}
|
||||
return out;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the cookie header properly in the Response
|
||||
* @param res An object which has a headers property
|
||||
* @param cookie Cookie to set
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```ts
|
||||
* setCookie(response, { name: 'deno', value: 'runtime',
|
||||
* httpOnly: true, secure: true, maxAge: 2, domain: "deno.land" });
|
||||
* ```
|
||||
*/
|
||||
export function setCookie(res: { headers?: Headers }, cookie: Cookie): void {
|
||||
if (!res.headers) {
|
||||
res.headers = new Headers();
|
||||
}
|
||||
// TODO (zekth) : Add proper parsing of Set-Cookie headers
|
||||
// Parsing cookie headers to make consistent set-cookie header
|
||||
// ref: https://tools.ietf.org/html/rfc6265#section-4.1.1
|
||||
const v = toString(cookie);
|
||||
if (v) {
|
||||
res.headers.append("Set-Cookie", v);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the cookie header properly in the Response to delete it
|
||||
* @param res Server Response
|
||||
* @param name Name of the cookie to Delete
|
||||
* Example:
|
||||
*
|
||||
* deleteCookie(res,'foo');
|
||||
*/
|
||||
export function deleteCookie(res: { headers?: Headers }, name: string): void {
|
||||
setCookie(res, {
|
||||
name: name,
|
||||
value: "",
|
||||
expires: new Date(0),
|
||||
});
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
// Loaded from https://deno.land/std@0.77.0/io/mod.ts
|
||||
|
||||
|
||||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
export * from "./bufio.ts";
|
||||
export * from "./ioutil.ts";
|
||||
export * from "./readers.ts";
|
||||
export * from "./writers.ts";
|
||||
export * from "./streams.ts";
|
@ -0,0 +1,44 @@
|
||||
// Loaded from https://deno.land/x/ramda@v0.27.2/source/internal/_clone.js
|
||||
|
||||
|
||||
import _cloneRegExp from './_cloneRegExp.js';
|
||||
import type from '../type.js';
|
||||
|
||||
|
||||
/**
|
||||
* Copies an object.
|
||||
*
|
||||
* @private
|
||||
* @param {*} value The value to be copied
|
||||
* @param {Array} refFrom Array containing the source references
|
||||
* @param {Array} refTo Array containing the copied source references
|
||||
* @param {Boolean} deep Whether or not to perform deep cloning.
|
||||
* @return {*} The copied value.
|
||||
*/
|
||||
export default function _clone(value, refFrom, refTo, deep) {
|
||||
var copy = function copy(copiedValue) {
|
||||
var len = refFrom.length;
|
||||
var idx = 0;
|
||||
while (idx < len) {
|
||||
if (value === refFrom[idx]) {
|
||||
return refTo[idx];
|
||||
}
|
||||
idx += 1;
|
||||
}
|
||||
refFrom[idx] = value;
|
||||
refTo[idx] = copiedValue;
|
||||
for (var key in value) {
|
||||
if (value.hasOwnProperty(key)) {
|
||||
copiedValue[key] = deep ? _clone(value[key], refFrom, refTo, true) : value[key];
|
||||
}
|
||||
}
|
||||
return copiedValue;
|
||||
};
|
||||
switch (type(value)) {
|
||||
case 'Object': return copy(Object.create(Object.getPrototypeOf(value)));
|
||||
case 'Array': return copy([]);
|
||||
case 'Date': return new Date(value.valueOf());
|
||||
case 'RegExp': return _cloneRegExp(value);
|
||||
default: return value;
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
// Loaded from https://deno.land/x/ramda@v0.27.2/source/pick.js
|
||||
|
||||
|
||||
import _curry2 from './internal/_curry2.js';
|
||||
|
||||
|
||||
/**
|
||||
* Returns a partial copy of an object containing only the keys specified. If
|
||||
* the key does not exist, the property is ignored.
|
||||
*
|
||||
* @func
|
||||
* @memberOf R
|
||||
* @since v0.1.0
|
||||
* @category Object
|
||||
* @sig [k] -> {k: v} -> {k: v}
|
||||
* @param {Array} names an array of String property names to copy onto a new object
|
||||
* @param {Object} obj The object to copy from
|
||||
* @return {Object} A new object with only properties from `names` on it.
|
||||
* @see R.omit, R.props
|
||||
* @example
|
||||
*
|
||||
* R.pick(['a', 'd'], {a: 1, b: 2, c: 3, d: 4}); //=> {a: 1, d: 4}
|
||||
* R.pick(['a', 'e', 'f'], {a: 1, b: 2, c: 3, d: 4}); //=> {a: 1}
|
||||
*/
|
||||
var pick = _curry2(function pick(names, obj) {
|
||||
var result = {};
|
||||
var idx = 0;
|
||||
while (idx < names.length) {
|
||||
if (names[idx] in obj) {
|
||||
result[names[idx]] = obj[names[idx]];
|
||||
}
|
||||
idx += 1;
|
||||
}
|
||||
return result;
|
||||
});
|
||||
export default pick;
|
@ -0,0 +1,84 @@
|
||||
// Loaded from https://deno.land/x/denodb@v1.0.18/lib/relationships.ts
|
||||
|
||||
|
||||
import type { ModelSchema } from "./model.ts";
|
||||
import { DataTypes, FieldTypeString, RelationshipType } from "./data-types.ts";
|
||||
import { PivotModel } from "./model-pivot.ts";
|
||||
|
||||
type RelationshipOptions = {
|
||||
primaryKey?: string;
|
||||
foreignKey?: string;
|
||||
};
|
||||
|
||||
export const Relationships = {
|
||||
/** Define a one-to-one or one-to-many relationship for a given model. */
|
||||
belongsTo(model: ModelSchema): RelationshipType {
|
||||
return {
|
||||
type: DataTypes.INTEGER,
|
||||
relationship: {
|
||||
kind: "single",
|
||||
model,
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
/** Add corresponding fields to each model for a one-to-one relationship. */
|
||||
oneToOne(
|
||||
modelA: ModelSchema,
|
||||
modelB: ModelSchema,
|
||||
options?: RelationshipOptions,
|
||||
) {
|
||||
let primaryKey = options?.primaryKey;
|
||||
let foreignKey = options?.foreignKey;
|
||||
|
||||
modelA.fields[primaryKey || `${modelB.name.toLowerCase()}Id`] = this
|
||||
.belongsTo(modelB);
|
||||
modelB.fields[foreignKey || `${modelA.name.toLowerCase()}Id`] = this
|
||||
.belongsTo(modelA);
|
||||
},
|
||||
|
||||
/** Generate a many-to-many pivot model for two given models.
|
||||
*
|
||||
* const AirportFlight = Relationships.manyToMany(Airport, Flight);
|
||||
*/
|
||||
manyToMany(
|
||||
modelA: ModelSchema,
|
||||
modelB: ModelSchema,
|
||||
options?: RelationshipOptions,
|
||||
): ModelSchema {
|
||||
let primaryKey = options?.primaryKey;
|
||||
let foreignKey = options?.foreignKey;
|
||||
|
||||
const pivotClassName = `${modelA.table}_${modelB.table}`;
|
||||
const modelAFieldName = primaryKey || `${modelA.name.toLowerCase()}Id`;
|
||||
const modelBFieldName = foreignKey || `${modelB.name.toLowerCase()}Id`;
|
||||
|
||||
class PivotClass extends PivotModel {
|
||||
static table = pivotClassName;
|
||||
|
||||
static fields = {
|
||||
id: {
|
||||
primaryKey: true,
|
||||
autoIncrement: true,
|
||||
},
|
||||
[modelAFieldName]: Relationships.belongsTo(modelA),
|
||||
[modelBFieldName]: Relationships.belongsTo(modelB),
|
||||
};
|
||||
|
||||
static _pivotsModels = {
|
||||
[modelA.name]: modelA,
|
||||
[modelB.name]: modelB,
|
||||
};
|
||||
|
||||
static _pivotsFields = {
|
||||
[modelA.name]: modelAFieldName,
|
||||
[modelB.name]: modelBFieldName,
|
||||
};
|
||||
}
|
||||
|
||||
modelA.pivot[modelB.name] = PivotClass;
|
||||
modelB.pivot[modelA.name] = PivotClass;
|
||||
|
||||
return PivotClass;
|
||||
},
|
||||
};
|
@ -0,0 +1,34 @@
|
||||
// Loaded from https://deno.land/x/ramda@v0.27.2/source/zipObj.js
|
||||
|
||||
|
||||
import _curry2 from './internal/_curry2.js';
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new object out of a list of keys and a list of values.
|
||||
* Key/value pairing is truncated to the length of the shorter of the two lists.
|
||||
* Note: `zipObj` is equivalent to `pipe(zip, fromPairs)`.
|
||||
*
|
||||
* @func
|
||||
* @memberOf R
|
||||
* @since v0.3.0
|
||||
* @category List
|
||||
* @sig [String] -> [*] -> {String: *}
|
||||
* @param {Array} keys The array that will be properties on the output object.
|
||||
* @param {Array} values The list of values on the output object.
|
||||
* @return {Object} The object made by pairing up same-indexed elements of `keys` and `values`.
|
||||
* @example
|
||||
*
|
||||
* R.zipObj(['a', 'b', 'c'], [1, 2, 3]); //=> {a: 1, b: 2, c: 3}
|
||||
*/
|
||||
var zipObj = _curry2(function zipObj(keys, values) {
|
||||
var idx = 0;
|
||||
var len = Math.min(keys.length, values.length);
|
||||
var out = {};
|
||||
while (idx < len) {
|
||||
out[keys[idx]] = values[idx];
|
||||
idx += 1;
|
||||
}
|
||||
return out;
|
||||
});
|
||||
export default zipObj;
|
@ -0,0 +1,185 @@
|
||||
// Loaded from https://deno.land/x/oak@v6.3.1/context.ts
|
||||
|
||||
|
||||
// Copyright 2018-2020 the oak authors. All rights reserved. MIT license.
|
||||
|
||||
import type { Application, State } from "./application.ts";
|
||||
import { Cookies } from "./cookies.ts";
|
||||
import { acceptable, acceptWebSocket, WebSocket } from "./deps.ts";
|
||||
import { createHttpError } from "./httpError.ts";
|
||||
import type { KeyStack } from "./keyStack.ts";
|
||||
import { Request } from "./request.ts";
|
||||
import { Response } from "./response.ts";
|
||||
import { send, SendOptions } from "./send.ts";
|
||||
import {
|
||||
ServerSentEventTarget,
|
||||
ServerSentEventTargetOptions,
|
||||
} from "./server_sent_event.ts";
|
||||
import type { ErrorStatus, ServerRequest } from "./types.d.ts";
|
||||
|
||||
export interface ContextSendOptions extends SendOptions {
|
||||
/** The filename to send, which will be resolved based on the other options.
|
||||
* If this property is omitted, the current context's `.request.url.pathname`
|
||||
* will be used. */
|
||||
path?: string;
|
||||
}
|
||||
|
||||
/** Provides context about the current request and response to middleware
|
||||
* functions. */
|
||||
// deno-lint-ignore no-explicit-any
|
||||
export class Context<S extends State = Record<string, any>> {
|
||||
#socket?: WebSocket;
|
||||
#sse?: ServerSentEventTarget;
|
||||
|
||||
/** A reference to the current application. */
|
||||
app: Application<State>;
|
||||
|
||||
/** An object which allows access to cookies, mediating both the request and
|
||||
* response. */
|
||||
cookies: Cookies;
|
||||
|
||||
/** Is `true` if the current connection is upgradeable to a web socket.
|
||||
* Otherwise the value is `false`. Use `.upgrade()` to upgrade the connection
|
||||
* and return the web socket. */
|
||||
get isUpgradable(): boolean {
|
||||
return acceptable(this.request);
|
||||
}
|
||||
|
||||
/** Determines if the request should be responded to. If `false` when the
|
||||
* middleware completes processing, the response will not be sent back to the
|
||||
* requestor. Typically this is used if the middleware will take over low
|
||||
* level processing of requests and responses, for example if using web
|
||||
* sockets. This automatically gets set to `false` when the context is
|
||||
* upgraded to a web socket via the `.upgrade()` method.
|
||||
*
|
||||
* The default is `true`. */
|
||||
respond: boolean;
|
||||
|
||||
/** An object which contains information about the current request. */
|
||||
request: Request;
|
||||
|
||||
/** An object which contains information about the response that will be sent
|
||||
* when the middleware finishes processing. */
|
||||
response: Response;
|
||||
|
||||
/** If the the current context has been upgraded, then this will be set to
|
||||
* with the web socket, otherwise it is `undefined`. */
|
||||
get socket(): WebSocket | undefined {
|
||||
return this.#socket;
|
||||
}
|
||||
|
||||
/** The object to pass state to front-end views. This can be typed by
|
||||
* supplying the generic state argument when creating a new app. For
|
||||
* example:
|
||||
*
|
||||
* ```ts
|
||||
* const app = new Application<{ foo: string }>();
|
||||
* ```
|
||||
*
|
||||
* Or can be contextually inferred based on setting an initial state object:
|
||||
*
|
||||
* ```ts
|
||||
* const app = new Application({ state: { foo: "bar" } });
|
||||
* ```
|
||||
*/
|
||||
state: S;
|
||||
|
||||
constructor(
|
||||
app: Application<S>,
|
||||
serverRequest: ServerRequest,
|
||||
secure = false,
|
||||
) {
|
||||
this.app = app;
|
||||
this.state = app.state;
|
||||
this.request = new Request(serverRequest, app.proxy, secure);
|
||||
this.respond = true;
|
||||
this.response = new Response(this.request);
|
||||
this.cookies = new Cookies(this.request, this.response, {
|
||||
keys: this.app.keys as KeyStack | undefined,
|
||||
secure: this.request.secure,
|
||||
});
|
||||
}
|
||||
|
||||
/** Asserts the condition and if the condition fails, creates an HTTP error
|
||||
* with the provided status (which defaults to `500`). The error status by
|
||||
* default will be set on the `.response.status`.
|
||||
*/
|
||||
assert(
|
||||
// deno-lint-ignore no-explicit-any
|
||||
condition: any,
|
||||
errorStatus: ErrorStatus = 500,
|
||||
message?: string,
|
||||
props?: Record<string, unknown>,
|
||||
): asserts condition {
|
||||
if (condition) {
|
||||
return;
|
||||
}
|
||||
const err = createHttpError(errorStatus, message);
|
||||
if (props) {
|
||||
Object.assign(err, props);
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
|
||||
/** Asynchronously fulfill a response with a file from the local file
|
||||
* system.
|
||||
*
|
||||
* If the `options.path` is not supplied, the file to be sent will default
|
||||
* to this `.request.url.pathname`.
|
||||
*
|
||||
* Requires Deno read permission. */
|
||||
send(options: ContextSendOptions): Promise<string | undefined> {
|
||||
const { path = this.request.url.pathname, ...sendOptions } = options;
|
||||
return send(this, path, sendOptions);
|
||||
}
|
||||
|
||||
/** Convert the connection to stream events, returning an event target for
|
||||
* sending server sent events. Events dispatched on the returned target will
|
||||
* be sent to the client and be available in the client's `EventSource` that
|
||||
* initiated the connection.
|
||||
*
|
||||
* This will set `.respond` to `false`. */
|
||||
sendEvents(options?: ServerSentEventTargetOptions): ServerSentEventTarget {
|
||||
if (this.#sse) {
|
||||
return this.#sse;
|
||||
}
|
||||
this.respond = false;
|
||||
return this.#sse = new ServerSentEventTarget(
|
||||
this.app,
|
||||
this.request.serverRequest,
|
||||
options,
|
||||
);
|
||||
}
|
||||
|
||||
/** Create and throw an HTTP Error, which can be used to pass status
|
||||
* information which can be caught by other middleware to send more
|
||||
* meaningful error messages back to the client. The passed error status will
|
||||
* be set on the `.response.status` by default as well.
|
||||
*/
|
||||
throw(
|
||||
errorStatus: ErrorStatus,
|
||||
message?: string,
|
||||
props?: Record<string, unknown>,
|
||||
): never {
|
||||
const err = createHttpError(errorStatus, message);
|
||||
if (props) {
|
||||
Object.assign(err, props);
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
|
||||
/** Take the current request and upgrade it to a web socket, resolving with
|
||||
* the web socket object. This will set `.respond` to `false`. */
|
||||
async upgrade(): Promise<WebSocket> {
|
||||
if (this.#socket) {
|
||||
return this.#socket;
|
||||
}
|
||||
const { conn, r: bufReader, w: bufWriter, headers } =
|
||||
this.request.serverRequest;
|
||||
this.#socket = await acceptWebSocket(
|
||||
{ conn, bufReader, bufWriter, headers },
|
||||
);
|
||||
this.respond = false;
|
||||
return this.#socket;
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
// Loaded from https://deno.land/x/segno@v1.1.0/lib/validations/isHexadecimal.ts
|
||||
|
||||
|
||||
// @ts-ignore allowing typedoc to build
|
||||
import { assertString } from '../helpers/assertString.ts';
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
const hexadecimal = /^(0x|0h)?[0-9A-F]+$/i;
|
||||
|
||||
export const isHexadecimal = (str: string) => {
|
||||
assertString(str);
|
||||
return hexadecimal.test(str);
|
||||
};
|
@ -0,0 +1,34 @@
|
||||
// Loaded from https://deno.land/x/ramda@v0.27.2/source/update.js
|
||||
|
||||
|
||||
import _curry3 from './internal/_curry3.js';
|
||||
import adjust from './adjust.js';
|
||||
import always from './always.js';
|
||||
|
||||
|
||||
/**
|
||||
* Returns a new copy of the array with the element at the provided index
|
||||
* replaced with the given value.
|
||||
*
|
||||
* @func
|
||||
* @memberOf R
|
||||
* @since v0.14.0
|
||||
* @category List
|
||||
* @sig Number -> a -> [a] -> [a]
|
||||
* @param {Number} idx The index to update.
|
||||
* @param {*} x The value to exist at the given index of the returned array.
|
||||
* @param {Array|Arguments} list The source array-like object to be updated.
|
||||
* @return {Array} A copy of `list` with the value at index `idx` replaced with `x`.
|
||||
* @see R.adjust
|
||||
* @example
|
||||
*
|
||||
* R.update(1, '_', ['a', 'b', 'c']); //=> ['a', '_', 'c']
|
||||
* R.update(-1, '_', ['a', 'b', 'c']); //=> ['a', 'b', '_']
|
||||
* @symb R.update(-1, a, [b, c]) = [b, a]
|
||||
* @symb R.update(0, a, [b, c]) = [a, c]
|
||||
* @symb R.update(1, a, [b, c]) = [b, a]
|
||||
*/
|
||||
var update = _curry3(function update(idx, x, list) {
|
||||
return adjust(idx, always(x), list);
|
||||
});
|
||||
export default update;
|
@ -0,0 +1,36 @@
|
||||
// Loaded from https://deno.land/x/ramda@v0.27.2/source/median.js
|
||||
|
||||
|
||||
import _curry1 from './internal/_curry1.js';
|
||||
import mean from './mean.js';
|
||||
|
||||
|
||||
/**
|
||||
* Returns the median of the given list of numbers.
|
||||
*
|
||||
* @func
|
||||
* @memberOf R
|
||||
* @since v0.14.0
|
||||
* @category Math
|
||||
* @sig [Number] -> Number
|
||||
* @param {Array} list
|
||||
* @return {Number}
|
||||
* @see R.mean
|
||||
* @example
|
||||
*
|
||||
* R.median([2, 9, 7]); //=> 7
|
||||
* R.median([7, 2, 10, 9]); //=> 8
|
||||
* R.median([]); //=> NaN
|
||||
*/
|
||||
var median = _curry1(function median(list) {
|
||||
var len = list.length;
|
||||
if (len === 0) {
|
||||
return NaN;
|
||||
}
|
||||
var width = 2 - len % 2;
|
||||
var idx = (len - width) / 2;
|
||||
return mean(Array.prototype.slice.call(list, 0).sort(function(a, b) {
|
||||
return a < b ? -1 : a > b ? 1 : 0;
|
||||
}).slice(idx, idx + width));
|
||||
});
|
||||
export default median;
|
@ -0,0 +1,42 @@
|
||||
// Loaded from https://deno.land/std@0.67.0/path/common.ts
|
||||
|
||||
|
||||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
/** This module is browser compatible. */
|
||||
|
||||
import { SEP } from "./separator.ts";
|
||||
|
||||
/** Determines the common path from a set of paths, using an optional separator,
|
||||
* which defaults to the OS default separator.
|
||||
*
|
||||
* import { common } from "https://deno.land/std/path/mod.ts";
|
||||
* const p = common([
|
||||
* "./deno/std/path/mod.ts",
|
||||
* "./deno/std/fs/mod.ts",
|
||||
* ]);
|
||||
* console.log(p); // "./deno/std/"
|
||||
*
|
||||
*/
|
||||
export function common(paths: string[], sep = SEP): string {
|
||||
const [first = "", ...remaining] = paths;
|
||||
if (first === "" || remaining.length === 0) {
|
||||
return first.substring(0, first.lastIndexOf(sep) + 1);
|
||||
}
|
||||
const parts = first.split(sep);
|
||||
|
||||
let endOfPrefix = parts.length;
|
||||
for (const path of remaining) {
|
||||
const compare = path.split(sep);
|
||||
for (let i = 0; i < endOfPrefix; i++) {
|
||||
if (compare[i] !== parts[i]) {
|
||||
endOfPrefix = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (endOfPrefix === 0) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
const prefix = parts.slice(0, endOfPrefix).join(sep);
|
||||
return prefix.endsWith(sep) ? prefix : `${prefix}${sep}`;
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
// Loaded from https://deno.land/x/segno@v1.1.0/lib/validations/isBoolean.ts
|
||||
|
||||
|
||||
// @ts-ignore allowing typedoc to build
|
||||
import { assertString } from '../helpers/assertString.ts';
|
||||
|
||||
export const isBoolean = (str: string) => {
|
||||
assertString(str);
|
||||
return ['true', 'false', '1', '0'].indexOf(str) >= 0;
|
||||
};
|
@ -0,0 +1,4 @@
|
||||
// Loaded from https://deno.land/x/mongo@v0.20.0/src/collection/mod.ts
|
||||
|
||||
|
||||
export { Collection } from "./collection.ts";
|
@ -0,0 +1,42 @@
|
||||
// Loaded from https://deno.land/std@0.80.0/encoding/_yaml/type/bool.ts
|
||||
|
||||
|
||||
// Ported from js-yaml v3.13.1:
|
||||
// https://github.com/nodeca/js-yaml/commit/665aadda42349dcae869f12040d9b10ef18d12da
|
||||
// Copyright 2011-2015 by Vitaly Puzrin. All rights reserved. MIT license.
|
||||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
import { Type } from "../type.ts";
|
||||
import { isBoolean } from "../utils.ts";
|
||||
|
||||
function resolveYamlBoolean(data: string): boolean {
|
||||
const max = data.length;
|
||||
|
||||
return (
|
||||
(max === 4 && (data === "true" || data === "True" || data === "TRUE")) ||
|
||||
(max === 5 && (data === "false" || data === "False" || data === "FALSE"))
|
||||
);
|
||||
}
|
||||
|
||||
function constructYamlBoolean(data: string): boolean {
|
||||
return data === "true" || data === "True" || data === "TRUE";
|
||||
}
|
||||
|
||||
export const bool = new Type("tag:yaml.org,2002:bool", {
|
||||
construct: constructYamlBoolean,
|
||||
defaultStyle: "lowercase",
|
||||
kind: "scalar",
|
||||
predicate: isBoolean,
|
||||
represent: {
|
||||
lowercase(object: boolean): string {
|
||||
return object ? "true" : "false";
|
||||
},
|
||||
uppercase(object: boolean): string {
|
||||
return object ? "TRUE" : "FALSE";
|
||||
},
|
||||
camelcase(object: boolean): string {
|
||||
return object ? "True" : "False";
|
||||
},
|
||||
},
|
||||
resolve: resolveYamlBoolean,
|
||||
});
|
@ -0,0 +1,32 @@
|
||||
// Loaded from https://deno.land/x/ramda@v0.27.2/source/objOf.js
|
||||
|
||||
|
||||
import _curry2 from './internal/_curry2.js';
|
||||
|
||||
|
||||
/**
|
||||
* Creates an object containing a single key:value pair.
|
||||
*
|
||||
* @func
|
||||
* @memberOf R
|
||||
* @since v0.18.0
|
||||
* @category Object
|
||||
* @sig String -> a -> {String:a}
|
||||
* @param {String} key
|
||||
* @param {*} val
|
||||
* @return {Object}
|
||||
* @see R.pair
|
||||
* @example
|
||||
*
|
||||
* const matchPhrases = R.compose(
|
||||
* R.objOf('must'),
|
||||
* R.map(R.objOf('match_phrase'))
|
||||
* );
|
||||
* matchPhrases(['foo', 'bar', 'baz']); //=> {must: [{match_phrase: 'foo'}, {match_phrase: 'bar'}, {match_phrase: 'baz'}]}
|
||||
*/
|
||||
var objOf = _curry2(function objOf(key, val) {
|
||||
var obj = {};
|
||||
obj[key] = val;
|
||||
return obj;
|
||||
});
|
||||
export default objOf;
|
@ -0,0 +1,35 @@
|
||||
// Loaded from https://deno.land/x/ramda@v0.27.2/source/partialObject.js
|
||||
|
||||
|
||||
import mergeDeepRight from './mergeDeepRight.js';
|
||||
import _curry2 from './internal/_curry2.js';
|
||||
|
||||
/**
|
||||
* Takes a function `f` and an object, and returns a function `g`.
|
||||
* When applied, `g` returns the result of applying `f` to the object
|
||||
* provided initially merged deeply (right) with the object provided as an argument to `g`.
|
||||
*
|
||||
* @func
|
||||
* @memberOf R
|
||||
* @category Function
|
||||
* @sig (({ a, b, c, ..., n }) -> x) -> { a, b, c, ...} -> ({ d, e, f, ..., n } -> x)
|
||||
* @param {Function} f
|
||||
* @param {Object} props
|
||||
* @return {Function}
|
||||
* @see R.partial, R.partialRight, R.curry, R.mergeDeepRight
|
||||
* @example
|
||||
*
|
||||
* const multiply2 = ({ a, b }) => a * b;
|
||||
* const double = R.partialObject(multiply2, { a: 2 });
|
||||
* double({ b: 2 }); //=> 4
|
||||
*
|
||||
* const greet = ({ salutation, title, firstName, lastName }) =>
|
||||
* salutation + ', ' + title + ' ' + firstName + ' ' + lastName + '!';
|
||||
*
|
||||
* const sayHello = R.partialObject(greet, { salutation: 'Hello' });
|
||||
* const sayHelloToMs = R.partialObject(sayHello, { title: 'Ms.' });
|
||||
* sayHelloToMs({ firstName: 'Jane', lastName: 'Jones' }); //=> 'Hello, Ms. Jane Jones!'
|
||||
* @symb R.partialObject(f, { a, b })({ c, d }) = f({ a, b, c, d })
|
||||
*/
|
||||
|
||||
export default _curry2((f, o) => (props) => f.call(this, mergeDeepRight(o, props)));
|
@ -0,0 +1,8 @@
|
||||
// Loaded from https://deno.land/x/graphql_deno@v15.0.0/lib/polyfills/objectValues.js
|
||||
|
||||
|
||||
/* eslint-disable no-redeclare */
|
||||
// $FlowFixMe workaround for: https://github.com/facebook/flow/issues/2221
|
||||
const objectValues = Object.values || (obj => Object.keys(obj).map(key => obj[key]));
|
||||
|
||||
export default objectValues;
|
@ -0,0 +1,77 @@
|
||||
// Loaded from https://deno.land/x/graphql_deno@v15.0.0/lib/utilities/separateOperations.js
|
||||
|
||||
|
||||
import { Kind } from '../language/kinds.js';
|
||||
import { visit } from '../language/visitor.js';
|
||||
|
||||
/**
|
||||
* separateOperations accepts a single AST document which may contain many
|
||||
* operations and fragments and returns a collection of AST documents each of
|
||||
* which contains a single operation as well the fragment definitions it
|
||||
* refers to.
|
||||
*/
|
||||
export function separateOperations(documentAST) {
|
||||
const operations = [];
|
||||
const depGraph = Object.create(null);
|
||||
let fromName; // Populate metadata and build a dependency graph.
|
||||
|
||||
visit(documentAST, {
|
||||
OperationDefinition(node) {
|
||||
fromName = opName(node);
|
||||
operations.push(node);
|
||||
},
|
||||
|
||||
FragmentDefinition(node) {
|
||||
fromName = node.name.value;
|
||||
},
|
||||
|
||||
FragmentSpread(node) {
|
||||
const toName = node.name.value;
|
||||
let dependents = depGraph[fromName];
|
||||
|
||||
if (dependents === undefined) {
|
||||
dependents = depGraph[fromName] = Object.create(null);
|
||||
}
|
||||
|
||||
dependents[toName] = true;
|
||||
}
|
||||
|
||||
}); // For each operation, produce a new synthesized AST which includes only what
|
||||
// is necessary for completing that operation.
|
||||
|
||||
const separatedDocumentASTs = Object.create(null);
|
||||
|
||||
for (const operation of operations) {
|
||||
const operationName = opName(operation);
|
||||
const dependencies = Object.create(null);
|
||||
collectTransitiveDependencies(dependencies, depGraph, operationName); // The list of definition nodes to be included for this operation, sorted
|
||||
// to retain the same order as the original document.
|
||||
|
||||
separatedDocumentASTs[operationName] = {
|
||||
kind: Kind.DOCUMENT,
|
||||
definitions: documentAST.definitions.filter(node => node === operation || node.kind === Kind.FRAGMENT_DEFINITION && dependencies[node.name.value])
|
||||
};
|
||||
}
|
||||
|
||||
return separatedDocumentASTs;
|
||||
}
|
||||
|
||||
// Provides the empty string for anonymous operations.
|
||||
function opName(operation) {
|
||||
return operation.name ? operation.name.value : '';
|
||||
} // From a dependency graph, collects a list of transitive dependencies by
|
||||
// recursing through a dependency graph.
|
||||
|
||||
|
||||
function collectTransitiveDependencies(collected, depGraph, fromName) {
|
||||
const immediateDeps = depGraph[fromName];
|
||||
|
||||
if (immediateDeps) {
|
||||
for (const toName of Object.keys(immediateDeps)) {
|
||||
if (!collected[toName]) {
|
||||
collected[toName] = true;
|
||||
collectTransitiveDependencies(collected, depGraph, toName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,205 @@
|
||||
// Loaded from https://deno.land/x/deno_image@v0.0.3/lib/decoders/fast-png/PNGEncoder.ts
|
||||
|
||||
|
||||
import { IOBuffer } from './iobuffer/IOBuffer.ts';
|
||||
import { deflate } from './pako/index.js';
|
||||
|
||||
import { pngSignature, crc } from './common.ts';
|
||||
import {
|
||||
DeflateFunctionOptions,
|
||||
IPNGEncoderOptions,
|
||||
IImageData,
|
||||
IDecodedPNG,
|
||||
PNGDataArray,
|
||||
BitDepth,
|
||||
} from './types.ts';
|
||||
import {
|
||||
ColorType,
|
||||
CompressionMethod,
|
||||
FilterMethod,
|
||||
InterlaceMethod,
|
||||
} from './internalTypes.ts';
|
||||
|
||||
const defaultZlibOptions: DeflateFunctionOptions = {
|
||||
level: 3,
|
||||
};
|
||||
|
||||
export default class PNGEncoder extends IOBuffer {
|
||||
private _png: IDecodedPNG;
|
||||
private _zlibOptions: DeflateFunctionOptions;
|
||||
private _colorType: ColorType;
|
||||
|
||||
public constructor(data: IImageData, options: IPNGEncoderOptions = {}) {
|
||||
super();
|
||||
this._colorType = ColorType.UNKNOWN;
|
||||
this._zlibOptions = Object.assign({}, defaultZlibOptions, options.zlib);
|
||||
this._png = this._checkData(data);
|
||||
this.setBigEndian();
|
||||
}
|
||||
|
||||
public encode(): Uint8Array {
|
||||
this.encodeSignature();
|
||||
this.encodeIHDR();
|
||||
this.encodeData();
|
||||
this.encodeIEND();
|
||||
return this.toArray();
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/PNG/#5PNG-file-signature
|
||||
private encodeSignature(): void {
|
||||
this.writeBytes(pngSignature);
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/PNG/#11IHDR
|
||||
private encodeIHDR(): void {
|
||||
this.writeUint32(13);
|
||||
|
||||
this.writeChars('IHDR');
|
||||
|
||||
this.writeUint32(this._png.width);
|
||||
this.writeUint32(this._png.height);
|
||||
this.writeByte(this._png.depth);
|
||||
this.writeByte(this._colorType);
|
||||
this.writeByte(CompressionMethod.DEFLATE);
|
||||
this.writeByte(FilterMethod.ADAPTIVE);
|
||||
this.writeByte(InterlaceMethod.NO_INTERLACE);
|
||||
|
||||
this.writeCrc(17);
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/PNG/#11IEND
|
||||
private encodeIEND(): void {
|
||||
this.writeUint32(0);
|
||||
|
||||
this.writeChars('IEND');
|
||||
|
||||
this.writeCrc(4);
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/PNG/#11IDAT
|
||||
private encodeIDAT(data: PNGDataArray): void {
|
||||
this.writeUint32(data.length);
|
||||
|
||||
this.writeChars('IDAT');
|
||||
|
||||
this.writeBytes(data);
|
||||
|
||||
this.writeCrc(data.length + 4);
|
||||
}
|
||||
|
||||
private encodeData(): void {
|
||||
const { width, height, channels, depth, data } = this._png;
|
||||
const slotsPerLine = channels * width;
|
||||
const newData = new IOBuffer().setBigEndian();
|
||||
let offset = 0;
|
||||
for (let i = 0; i < height; i++) {
|
||||
newData.writeByte(0); // no filter
|
||||
/* istanbul ignore else */
|
||||
if (depth === 8) {
|
||||
offset = writeDataBytes(data, newData, slotsPerLine, offset);
|
||||
} else if (depth === 16) {
|
||||
offset = writeDataUint16(data, newData, slotsPerLine, offset);
|
||||
} else {
|
||||
throw new Error('unreachable');
|
||||
}
|
||||
}
|
||||
const buffer = newData.toArray();
|
||||
const compressed = <Uint8Array>deflate(buffer, this._zlibOptions);
|
||||
this.encodeIDAT(compressed);
|
||||
}
|
||||
|
||||
private _checkData(data: IImageData): IDecodedPNG {
|
||||
const { colorType, channels, depth } = getColorType(data);
|
||||
const png: IDecodedPNG = {
|
||||
width: checkInteger(data.width, 'width'),
|
||||
height: checkInteger(data.height, 'height'),
|
||||
channels: channels,
|
||||
data: data.data,
|
||||
depth: depth,
|
||||
text: {},
|
||||
};
|
||||
this._colorType = colorType;
|
||||
const expectedSize = png.width * png.height * channels;
|
||||
if (png.data.length !== expectedSize) {
|
||||
throw new RangeError(
|
||||
`wrong data size. Found ${png.data.length}, expected ${expectedSize}`,
|
||||
);
|
||||
}
|
||||
return png;
|
||||
}
|
||||
|
||||
private writeCrc(length: number): void {
|
||||
this.writeUint32(
|
||||
crc(
|
||||
new Uint8Array(
|
||||
this.buffer,
|
||||
this.byteOffset + this.offset - length,
|
||||
length,
|
||||
),
|
||||
length,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function checkInteger(value: number, name: string): number {
|
||||
if (Number.isInteger(value) && value > 0) {
|
||||
return value;
|
||||
}
|
||||
throw new TypeError(`${name} must be a positive integer`);
|
||||
}
|
||||
|
||||
function getColorType(
|
||||
data: IImageData,
|
||||
): { channels: number; depth: BitDepth; colorType: ColorType } {
|
||||
const { channels = 4, depth = 8 } = data;
|
||||
if (channels !== 4 && channels !== 3 && channels !== 2 && channels !== 1) {
|
||||
throw new RangeError(`unsupported number of channels: ${channels}`);
|
||||
}
|
||||
if (depth !== 8 && depth !== 16) {
|
||||
throw new RangeError(`unsupported bit depth: ${depth}`);
|
||||
}
|
||||
|
||||
const returnValue = { channels, depth, colorType: ColorType.UNKNOWN };
|
||||
switch (channels) {
|
||||
case 4:
|
||||
returnValue.colorType = ColorType.TRUECOLOUR_ALPHA;
|
||||
break;
|
||||
case 3:
|
||||
returnValue.colorType = ColorType.TRUECOLOUR;
|
||||
break;
|
||||
case 1:
|
||||
returnValue.colorType = ColorType.GREYSCALE;
|
||||
break;
|
||||
case 2:
|
||||
returnValue.colorType = ColorType.GREYSCALE_ALPHA;
|
||||
break;
|
||||
default:
|
||||
throw new Error(`unsupported number of channels: ${channels}`);
|
||||
}
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
function writeDataBytes(
|
||||
data: PNGDataArray,
|
||||
newData: IOBuffer,
|
||||
slotsPerLine: number,
|
||||
offset: number,
|
||||
): number {
|
||||
for (let j = 0; j < slotsPerLine; j++) {
|
||||
newData.writeByte(data[offset++]);
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
function writeDataUint16(
|
||||
data: PNGDataArray,
|
||||
newData: IOBuffer,
|
||||
slotsPerLine: number,
|
||||
offset: number,
|
||||
): number {
|
||||
for (let j = 0; j < slotsPerLine; j++) {
|
||||
newData.writeUint16(data[offset++]);
|
||||
}
|
||||
return offset;
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
// Loaded from https://deno.land/x/ramda@v0.27.2/source/mergeWithKey.js
|
||||
|
||||
|
||||
import _curry3 from './internal/_curry3.js';
|
||||
import _has from './internal/_has.js';
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new object with the own properties of the two provided objects. If
|
||||
* a key exists in both objects, the provided function is applied to the key
|
||||
* and the values associated with the key in each object, with the result being
|
||||
* used as the value associated with the key in the returned object.
|
||||
*
|
||||
* @func
|
||||
* @memberOf R
|
||||
* @since v0.19.0
|
||||
* @category Object
|
||||
* @sig ((String, a, a) -> a) -> {a} -> {a} -> {a}
|
||||
* @param {Function} fn
|
||||
* @param {Object} l
|
||||
* @param {Object} r
|
||||
* @return {Object}
|
||||
* @see R.mergeDeepWithKey, R.merge, R.mergeWith
|
||||
* @example
|
||||
*
|
||||
* let concatValues = (k, l, r) => k == 'values' ? R.concat(l, r) : r
|
||||
* R.mergeWithKey(concatValues,
|
||||
* { a: true, thing: 'foo', values: [10, 20] },
|
||||
* { b: true, thing: 'bar', values: [15, 35] });
|
||||
* //=> { a: true, b: true, thing: 'bar', values: [10, 20, 15, 35] }
|
||||
* @symb R.mergeWithKey(f, { x: 1, y: 2 }, { y: 5, z: 3 }) = { x: 1, y: f('y', 2, 5), z: 3 }
|
||||
*/
|
||||
var mergeWithKey = _curry3(function mergeWithKey(fn, l, r) {
|
||||
var result = {};
|
||||
var k;
|
||||
|
||||
for (k in l) {
|
||||
if (_has(k, l)) {
|
||||
result[k] = _has(k, r) ? fn(k, l[k], r[k]) : l[k];
|
||||
}
|
||||
}
|
||||
|
||||
for (k in r) {
|
||||
if (_has(k, r) && !(_has(k, result))) {
|
||||
result[k] = r[k];
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
});
|
||||
export default mergeWithKey;
|
@ -0,0 +1,4 @@
|
||||
// Loaded from https://deno.land/x/abc@v1.2.4/vendor/https/deno.land/std/mime/multipart.ts
|
||||
|
||||
|
||||
export * from "https://deno.land/std@0.81.0/mime/multipart.ts";
|
@ -0,0 +1,13 @@
|
||||
// Loaded from https://deno.land/x/case/titleCase.ts
|
||||
|
||||
|
||||
import upperCase from "./upperCase.ts";
|
||||
import normalCase from "./normalCase.ts";
|
||||
|
||||
export default function titleCase(value: string, locale?: string): string {
|
||||
return normalCase(value, locale).replace(/^.| ./g, function (
|
||||
m: string,
|
||||
): string {
|
||||
return upperCase(m, locale);
|
||||
});
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
// Loaded from https://deno.land/std@0.67.0/path/_constants.ts
|
||||
|
||||
|
||||
// Copyright the Browserify authors. MIT License.
|
||||
// Ported from https://github.com/browserify/path-browserify/
|
||||
/** This module is browser compatible. */
|
||||
|
||||
// Alphabet chars.
|
||||
export const CHAR_UPPERCASE_A = 65; /* A */
|
||||
export const CHAR_LOWERCASE_A = 97; /* a */
|
||||
export const CHAR_UPPERCASE_Z = 90; /* Z */
|
||||
export const CHAR_LOWERCASE_Z = 122; /* z */
|
||||
|
||||
// Non-alphabetic chars.
|
||||
export const CHAR_DOT = 46; /* . */
|
||||
export const CHAR_FORWARD_SLASH = 47; /* / */
|
||||
export const CHAR_BACKWARD_SLASH = 92; /* \ */
|
||||
export const CHAR_VERTICAL_LINE = 124; /* | */
|
||||
export const CHAR_COLON = 58; /* : */
|
||||
export const CHAR_QUESTION_MARK = 63; /* ? */
|
||||
export const CHAR_UNDERSCORE = 95; /* _ */
|
||||
export const CHAR_LINE_FEED = 10; /* \n */
|
||||
export const CHAR_CARRIAGE_RETURN = 13; /* \r */
|
||||
export const CHAR_TAB = 9; /* \t */
|
||||
export const CHAR_FORM_FEED = 12; /* \f */
|
||||
export const CHAR_EXCLAMATION_MARK = 33; /* ! */
|
||||
export const CHAR_HASH = 35; /* # */
|
||||
export const CHAR_SPACE = 32; /* */
|
||||
export const CHAR_NO_BREAK_SPACE = 160; /* \u00A0 */
|
||||
export const CHAR_ZERO_WIDTH_NOBREAK_SPACE = 65279; /* \uFEFF */
|
||||
export const CHAR_LEFT_SQUARE_BRACKET = 91; /* [ */
|
||||
export const CHAR_RIGHT_SQUARE_BRACKET = 93; /* ] */
|
||||
export const CHAR_LEFT_ANGLE_BRACKET = 60; /* < */
|
||||
export const CHAR_RIGHT_ANGLE_BRACKET = 62; /* > */
|
||||
export const CHAR_LEFT_CURLY_BRACKET = 123; /* { */
|
||||
export const CHAR_RIGHT_CURLY_BRACKET = 125; /* } */
|
||||
export const CHAR_HYPHEN_MINUS = 45; /* - */
|
||||
export const CHAR_PLUS = 43; /* + */
|
||||
export const CHAR_DOUBLE_QUOTE = 34; /* " */
|
||||
export const CHAR_SINGLE_QUOTE = 39; /* ' */
|
||||
export const CHAR_PERCENT = 37; /* % */
|
||||
export const CHAR_SEMICOLON = 59; /* ; */
|
||||
export const CHAR_CIRCUMFLEX_ACCENT = 94; /* ^ */
|
||||
export const CHAR_GRAVE_ACCENT = 96; /* ` */
|
||||
export const CHAR_AT = 64; /* @ */
|
||||
export const CHAR_AMPERSAND = 38; /* & */
|
||||
export const CHAR_EQUAL = 61; /* = */
|
||||
|
||||
// Digits
|
||||
export const CHAR_0 = 48; /* 0 */
|
||||
export const CHAR_9 = 57; /* 9 */
|
||||
|
||||
let NATIVE_OS: typeof Deno.build.os = "linux";
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const navigator = (globalThis as any).navigator;
|
||||
if (globalThis.Deno != null) {
|
||||
NATIVE_OS = Deno.build.os;
|
||||
} else if (navigator?.appVersion?.includes?.("Win") ?? false) {
|
||||
NATIVE_OS = "windows";
|
||||
}
|
||||
// TODO(nayeemrmn): Improve OS detection in browsers beyond Windows.
|
||||
|
||||
export const isWindows = NATIVE_OS == "windows";
|
||||
|
||||
export { NATIVE_OS };
|
@ -0,0 +1,150 @@
|
||||
// Loaded from https://deno.land/x/god_crypto@v1.4.3/src/rsa/rsa_internal.ts
|
||||
|
||||
|
||||
import { power_mod } from "./../math.ts";
|
||||
import { eme_oaep_encode, eme_oaep_decode } from "./eme_oaep.ts";
|
||||
import { os2ip, i2osp } from "./primitives.ts";
|
||||
import { concat, random_bytes } from "./../helper.ts";
|
||||
import { ber_decode, ber_simple } from "./basic_encoding_rule.ts";
|
||||
import { RawBinary } from "../binary.ts";
|
||||
|
||||
/**
|
||||
* @param n public key modulus
|
||||
* @param e public key exponent
|
||||
* @param m message representative
|
||||
*/
|
||||
export function rsaep(n: bigint, e: bigint, m: bigint): bigint {
|
||||
return power_mod(m, e, n);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param n private key modulus
|
||||
* @param d private key exponent
|
||||
* @param c ciphertext representative
|
||||
*/
|
||||
export function rsadp(n: bigint, d: bigint, c: bigint): bigint {
|
||||
return power_mod(c, d, n);
|
||||
}
|
||||
|
||||
export function rsa_oaep_encrypt(
|
||||
bytes: number,
|
||||
n: bigint,
|
||||
e: bigint,
|
||||
m: Uint8Array,
|
||||
algorithm: "sha1" | "sha256",
|
||||
) {
|
||||
const em = eme_oaep_encode(new Uint8Array(0), m, bytes, algorithm);
|
||||
const msg = os2ip(em);
|
||||
const c = rsaep(n, e, msg);
|
||||
return i2osp(c, bytes);
|
||||
}
|
||||
|
||||
export function rsa_oaep_decrypt(
|
||||
bytes: number,
|
||||
n: bigint,
|
||||
d: bigint,
|
||||
c: Uint8Array,
|
||||
algorithm: "sha1" | "sha256",
|
||||
) {
|
||||
const em = rsadp(n, d, os2ip(c));
|
||||
const m = eme_oaep_decode(
|
||||
new Uint8Array(0),
|
||||
i2osp(em, bytes),
|
||||
bytes,
|
||||
algorithm,
|
||||
);
|
||||
return m;
|
||||
}
|
||||
|
||||
export function rsa_pkcs1_encrypt(
|
||||
bytes: number,
|
||||
n: bigint,
|
||||
e: bigint,
|
||||
m: Uint8Array,
|
||||
) {
|
||||
const p = concat([0x00, 0x02], random_bytes(bytes - m.length - 3), [0x00], m);
|
||||
const msg = os2ip(p);
|
||||
const c = rsaep(n, e, msg);
|
||||
return i2osp(c, bytes);
|
||||
}
|
||||
|
||||
export function rsa_pkcs1_decrypt(
|
||||
bytes: number,
|
||||
n: bigint,
|
||||
d: bigint,
|
||||
c: Uint8Array,
|
||||
) {
|
||||
const em = i2osp(rsadp(n, d, os2ip(c)), bytes);
|
||||
|
||||
if (em[0] !== 0) throw "Decryption error";
|
||||
if (em[1] !== 0x02) throw "Decryption error";
|
||||
|
||||
let psCursor = 2;
|
||||
for (; psCursor < em.length; psCursor++) {
|
||||
if (em[psCursor] === 0x00) break;
|
||||
}
|
||||
|
||||
if (psCursor < 10) throw "Decryption error";
|
||||
|
||||
return em.slice(psCursor + 1);
|
||||
}
|
||||
|
||||
export function rsa_pkcs1_verify(
|
||||
bytes: number,
|
||||
n: bigint,
|
||||
d: bigint,
|
||||
s: Uint8Array,
|
||||
m: Uint8Array,
|
||||
): boolean {
|
||||
let em = i2osp(rsadp(n, d, os2ip(s)), bytes);
|
||||
|
||||
if (em[0] !== 0) throw "Decryption error";
|
||||
if (em[1] !== 0x01) throw "Decryption error";
|
||||
|
||||
let psCursor = 2;
|
||||
for (; psCursor < em.length; psCursor++) {
|
||||
if (em[psCursor] === 0x00) break;
|
||||
}
|
||||
|
||||
if (psCursor < 10) throw "Decryption error";
|
||||
|
||||
// Removing padding
|
||||
em = em.slice(psCursor + 1);
|
||||
|
||||
// Parsing the BER
|
||||
const ber: [[number, null], Uint8Array] = ber_simple(ber_decode(em)) as any;
|
||||
const decryptedMessage = ber[1];
|
||||
|
||||
// Comparing the value
|
||||
if (decryptedMessage.length !== m.length) return false;
|
||||
for (let i = 0; i < decryptedMessage.length; i++) {
|
||||
if (decryptedMessage[i] !== m[i]) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
export function rsa_pkcs1_sign(
|
||||
bytes: number,
|
||||
n: bigint,
|
||||
d: bigint,
|
||||
message: Uint8Array,
|
||||
): RawBinary {
|
||||
// deno-fmt-ignore
|
||||
const oid = [0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00]
|
||||
const der = [
|
||||
0x30,
|
||||
message.length + 2 + oid.length,
|
||||
...oid,
|
||||
0x04,
|
||||
message.length,
|
||||
...message,
|
||||
];
|
||||
|
||||
const ps = new Array(bytes - 3 - der.length).fill(0xff);
|
||||
const em = new Uint8Array([0x00, 0x01, ...ps, 0x00, ...der]);
|
||||
|
||||
const msg = os2ip(em);
|
||||
const c = rsaep(n, d, msg);
|
||||
return new RawBinary(i2osp(c, bytes));
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
// Loaded from https://deno.land/std@0.80.0/_util/assert.ts
|
||||
|
||||
|
||||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
export class DenoStdInternalError extends Error {
|
||||
constructor(message: string) {
|
||||
super(message);
|
||||
this.name = "DenoStdInternalError";
|
||||
}
|
||||
}
|
||||
|
||||
/** Make an assertion, if not `true`, then throw. */
|
||||
export function assert(expr: unknown, msg = ""): asserts expr {
|
||||
if (!expr) {
|
||||
throw new DenoStdInternalError(msg);
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
// Loaded from https://deno.land/x/deno_image@v0.0.3/lib/decoders/fast-png/iobuffer/utf8.ts
|
||||
|
||||
|
||||
const decoder = new TextDecoder('utf-8');
|
||||
|
||||
export function decode(bytes: Uint8Array): string {
|
||||
return decoder.decode(bytes);
|
||||
}
|
||||
|
||||
const encoder = new TextEncoder();
|
||||
|
||||
export function encode(str: string): Uint8Array {
|
||||
return encoder.encode(str);
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user