mirror of
https://github.com/kou029w/_.git
synced 2025-01-31 06:18:07 +00:00
Kohei Watanabe
b755568571
git-subtree-dir: deno git-subtree-mainline:30663abe62
git-subtree-split:eb9915af3e
5640 lines
184 KiB
JavaScript
5640 lines
184 KiB
JavaScript
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
|
|
|
// This is a specialised implementation of a System module loader.
|
|
|
|
"use strict";
|
|
|
|
// @ts-nocheck
|
|
/* eslint-disable */
|
|
let System, __instantiateAsync, __instantiate;
|
|
|
|
(() => {
|
|
const r = new Map();
|
|
|
|
System = {
|
|
register(id, d, f) {
|
|
r.set(id, { d, f, exp: {} });
|
|
},
|
|
};
|
|
|
|
async function dI(mid, src) {
|
|
let id = mid.replace(/\.\w+$/i, "");
|
|
if (id.includes("./")) {
|
|
const [o, ...ia] = id.split("/").reverse(),
|
|
[, ...sa] = src.split("/").reverse(),
|
|
oa = [o];
|
|
let s = 0,
|
|
i;
|
|
while ((i = ia.shift())) {
|
|
if (i === "..") s++;
|
|
else if (i === ".") break;
|
|
else oa.push(i);
|
|
}
|
|
if (s < sa.length) oa.push(...sa.slice(s));
|
|
id = oa.reverse().join("/");
|
|
}
|
|
return r.has(id) ? gExpA(id) : import(mid);
|
|
}
|
|
|
|
function gC(id, main) {
|
|
return {
|
|
id,
|
|
import: (m) => dI(m, id),
|
|
meta: { url: id, main },
|
|
};
|
|
}
|
|
|
|
function gE(exp) {
|
|
return (id, v) => {
|
|
v = typeof id === "string" ? { [id]: v } : id;
|
|
for (const [id, value] of Object.entries(v)) {
|
|
Object.defineProperty(exp, id, {
|
|
value,
|
|
writable: true,
|
|
enumerable: true,
|
|
});
|
|
}
|
|
};
|
|
}
|
|
|
|
function rF(main) {
|
|
for (const [id, m] of r.entries()) {
|
|
const { f, exp } = m;
|
|
const { execute: e, setters: s } = f(gE(exp), gC(id, id === main));
|
|
delete m.f;
|
|
m.e = e;
|
|
m.s = s;
|
|
}
|
|
}
|
|
|
|
async function gExpA(id) {
|
|
if (!r.has(id)) return;
|
|
const m = r.get(id);
|
|
if (m.s) {
|
|
const { d, e, s } = m;
|
|
delete m.s;
|
|
delete m.e;
|
|
for (let i = 0; i < s.length; i++) s[i](await gExpA(d[i]));
|
|
const r = e();
|
|
if (r) await r;
|
|
}
|
|
return m.exp;
|
|
}
|
|
|
|
function gExp(id) {
|
|
if (!r.has(id)) return;
|
|
const m = r.get(id);
|
|
if (m.s) {
|
|
const { d, e, s } = m;
|
|
delete m.s;
|
|
delete m.e;
|
|
for (let i = 0; i < s.length; i++) s[i](gExp(d[i]));
|
|
e();
|
|
}
|
|
return m.exp;
|
|
}
|
|
|
|
__instantiateAsync = async (m) => {
|
|
System = __instantiateAsync = __instantiate = undefined;
|
|
rF(m);
|
|
return gExpA(m);
|
|
};
|
|
|
|
__instantiate = (m) => {
|
|
System = __instantiateAsync = __instantiate = undefined;
|
|
rF(m);
|
|
return gExp(m);
|
|
};
|
|
})();
|
|
|
|
System.register(
|
|
"https://deno.land/std@0.56.0/encoding/utf8",
|
|
[],
|
|
function (exports_1, context_1) {
|
|
"use strict";
|
|
var encoder, decoder;
|
|
var __moduleName = context_1 && context_1.id;
|
|
/** Shorthand for new TextEncoder().encode() */
|
|
function encode(input) {
|
|
return encoder.encode(input);
|
|
}
|
|
exports_1("encode", encode);
|
|
/** Shorthand for new TextDecoder().decode() */
|
|
function decode(input) {
|
|
return decoder.decode(input);
|
|
}
|
|
exports_1("decode", decode);
|
|
return {
|
|
setters: [],
|
|
execute: function () {
|
|
/** A default TextEncoder instance */
|
|
exports_1("encoder", encoder = new TextEncoder());
|
|
/** A default TextDecoder instance */
|
|
exports_1("decoder", decoder = new TextDecoder());
|
|
},
|
|
};
|
|
},
|
|
);
|
|
// Copyright the Browserify authors. MIT License.
|
|
// Ported from https://github.com/browserify/path-browserify/
|
|
/** This module is browser compatible. */
|
|
System.register(
|
|
"https://deno.land/std@0.56.0/path/_constants",
|
|
[],
|
|
function (exports_2, context_2) {
|
|
"use strict";
|
|
var CHAR_UPPERCASE_A,
|
|
CHAR_LOWERCASE_A,
|
|
CHAR_UPPERCASE_Z,
|
|
CHAR_LOWERCASE_Z,
|
|
CHAR_DOT,
|
|
CHAR_FORWARD_SLASH,
|
|
CHAR_BACKWARD_SLASH,
|
|
CHAR_VERTICAL_LINE,
|
|
CHAR_COLON,
|
|
CHAR_QUESTION_MARK,
|
|
CHAR_UNDERSCORE,
|
|
CHAR_LINE_FEED,
|
|
CHAR_CARRIAGE_RETURN,
|
|
CHAR_TAB,
|
|
CHAR_FORM_FEED,
|
|
CHAR_EXCLAMATION_MARK,
|
|
CHAR_HASH,
|
|
CHAR_SPACE,
|
|
CHAR_NO_BREAK_SPACE,
|
|
CHAR_ZERO_WIDTH_NOBREAK_SPACE,
|
|
CHAR_LEFT_SQUARE_BRACKET,
|
|
CHAR_RIGHT_SQUARE_BRACKET,
|
|
CHAR_LEFT_ANGLE_BRACKET,
|
|
CHAR_RIGHT_ANGLE_BRACKET,
|
|
CHAR_LEFT_CURLY_BRACKET,
|
|
CHAR_RIGHT_CURLY_BRACKET,
|
|
CHAR_HYPHEN_MINUS,
|
|
CHAR_PLUS,
|
|
CHAR_DOUBLE_QUOTE,
|
|
CHAR_SINGLE_QUOTE,
|
|
CHAR_PERCENT,
|
|
CHAR_SEMICOLON,
|
|
CHAR_CIRCUMFLEX_ACCENT,
|
|
CHAR_GRAVE_ACCENT,
|
|
CHAR_AT,
|
|
CHAR_AMPERSAND,
|
|
CHAR_EQUAL,
|
|
CHAR_0,
|
|
CHAR_9,
|
|
navigator,
|
|
isWindows;
|
|
var __moduleName = context_2 && context_2.id;
|
|
return {
|
|
setters: [],
|
|
execute: function () {
|
|
// Alphabet chars.
|
|
exports_2("CHAR_UPPERCASE_A", CHAR_UPPERCASE_A = 65); /* A */
|
|
exports_2("CHAR_LOWERCASE_A", CHAR_LOWERCASE_A = 97); /* a */
|
|
exports_2("CHAR_UPPERCASE_Z", CHAR_UPPERCASE_Z = 90); /* Z */
|
|
exports_2("CHAR_LOWERCASE_Z", CHAR_LOWERCASE_Z = 122); /* z */
|
|
// Non-alphabetic chars.
|
|
exports_2("CHAR_DOT", CHAR_DOT = 46); /* . */
|
|
exports_2("CHAR_FORWARD_SLASH", CHAR_FORWARD_SLASH = 47); /* / */
|
|
exports_2("CHAR_BACKWARD_SLASH", CHAR_BACKWARD_SLASH = 92); /* \ */
|
|
exports_2("CHAR_VERTICAL_LINE", CHAR_VERTICAL_LINE = 124); /* | */
|
|
exports_2("CHAR_COLON", CHAR_COLON = 58); /* : */
|
|
exports_2("CHAR_QUESTION_MARK", CHAR_QUESTION_MARK = 63); /* ? */
|
|
exports_2("CHAR_UNDERSCORE", CHAR_UNDERSCORE = 95); /* _ */
|
|
exports_2("CHAR_LINE_FEED", CHAR_LINE_FEED = 10); /* \n */
|
|
exports_2("CHAR_CARRIAGE_RETURN", CHAR_CARRIAGE_RETURN = 13); /* \r */
|
|
exports_2("CHAR_TAB", CHAR_TAB = 9); /* \t */
|
|
exports_2("CHAR_FORM_FEED", CHAR_FORM_FEED = 12); /* \f */
|
|
exports_2("CHAR_EXCLAMATION_MARK", CHAR_EXCLAMATION_MARK = 33); /* ! */
|
|
exports_2("CHAR_HASH", CHAR_HASH = 35); /* # */
|
|
exports_2("CHAR_SPACE", CHAR_SPACE = 32); /* */
|
|
exports_2(
|
|
"CHAR_NO_BREAK_SPACE",
|
|
CHAR_NO_BREAK_SPACE = 160,
|
|
); /* \u00A0 */
|
|
exports_2(
|
|
"CHAR_ZERO_WIDTH_NOBREAK_SPACE",
|
|
CHAR_ZERO_WIDTH_NOBREAK_SPACE = 65279,
|
|
); /* \uFEFF */
|
|
exports_2(
|
|
"CHAR_LEFT_SQUARE_BRACKET",
|
|
CHAR_LEFT_SQUARE_BRACKET = 91,
|
|
); /* [ */
|
|
exports_2(
|
|
"CHAR_RIGHT_SQUARE_BRACKET",
|
|
CHAR_RIGHT_SQUARE_BRACKET = 93,
|
|
); /* ] */
|
|
exports_2(
|
|
"CHAR_LEFT_ANGLE_BRACKET",
|
|
CHAR_LEFT_ANGLE_BRACKET = 60,
|
|
); /* < */
|
|
exports_2(
|
|
"CHAR_RIGHT_ANGLE_BRACKET",
|
|
CHAR_RIGHT_ANGLE_BRACKET = 62,
|
|
); /* > */
|
|
exports_2(
|
|
"CHAR_LEFT_CURLY_BRACKET",
|
|
CHAR_LEFT_CURLY_BRACKET = 123,
|
|
); /* { */
|
|
exports_2(
|
|
"CHAR_RIGHT_CURLY_BRACKET",
|
|
CHAR_RIGHT_CURLY_BRACKET = 125,
|
|
); /* } */
|
|
exports_2("CHAR_HYPHEN_MINUS", CHAR_HYPHEN_MINUS = 45); /* - */
|
|
exports_2("CHAR_PLUS", CHAR_PLUS = 43); /* + */
|
|
exports_2("CHAR_DOUBLE_QUOTE", CHAR_DOUBLE_QUOTE = 34); /* " */
|
|
exports_2("CHAR_SINGLE_QUOTE", CHAR_SINGLE_QUOTE = 39); /* ' */
|
|
exports_2("CHAR_PERCENT", CHAR_PERCENT = 37); /* % */
|
|
exports_2("CHAR_SEMICOLON", CHAR_SEMICOLON = 59); /* ; */
|
|
exports_2(
|
|
"CHAR_CIRCUMFLEX_ACCENT",
|
|
CHAR_CIRCUMFLEX_ACCENT = 94,
|
|
); /* ^ */
|
|
exports_2("CHAR_GRAVE_ACCENT", CHAR_GRAVE_ACCENT = 96); /* ` */
|
|
exports_2("CHAR_AT", CHAR_AT = 64); /* @ */
|
|
exports_2("CHAR_AMPERSAND", CHAR_AMPERSAND = 38); /* & */
|
|
exports_2("CHAR_EQUAL", CHAR_EQUAL = 61); /* = */
|
|
// Digits
|
|
exports_2("CHAR_0", CHAR_0 = 48); /* 0 */
|
|
exports_2("CHAR_9", CHAR_9 = 57); /* 9 */
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
navigator = globalThis.navigator;
|
|
isWindows = false;
|
|
exports_2("isWindows", isWindows);
|
|
if (globalThis.Deno != null) {
|
|
exports_2("isWindows", isWindows = Deno.build.os == "windows");
|
|
} else if (navigator?.appVersion != null) {
|
|
exports_2(
|
|
"isWindows",
|
|
isWindows = navigator.appVersion.includes("Win"),
|
|
);
|
|
}
|
|
},
|
|
};
|
|
},
|
|
);
|
|
/** This module is browser compatible. */
|
|
System.register(
|
|
"https://deno.land/std@0.56.0/path/_interface",
|
|
[],
|
|
function (exports_3, context_3) {
|
|
"use strict";
|
|
var __moduleName = context_3 && context_3.id;
|
|
return {
|
|
setters: [],
|
|
execute: function () {
|
|
},
|
|
};
|
|
},
|
|
);
|
|
// Copyright the Browserify authors. MIT License.
|
|
// Ported from https://github.com/browserify/path-browserify/
|
|
/** This module is browser compatible. */
|
|
System.register(
|
|
"https://deno.land/std@0.56.0/path/_util",
|
|
["https://deno.land/std@0.56.0/path/_constants"],
|
|
function (exports_4, context_4) {
|
|
"use strict";
|
|
var _constants_ts_1;
|
|
var __moduleName = context_4 && context_4.id;
|
|
function assertPath(path) {
|
|
if (typeof path !== "string") {
|
|
throw new TypeError(
|
|
`Path must be a string. Received ${JSON.stringify(path)}`,
|
|
);
|
|
}
|
|
}
|
|
exports_4("assertPath", assertPath);
|
|
function isPosixPathSeparator(code) {
|
|
return code === _constants_ts_1.CHAR_FORWARD_SLASH;
|
|
}
|
|
exports_4("isPosixPathSeparator", isPosixPathSeparator);
|
|
function isPathSeparator(code) {
|
|
return isPosixPathSeparator(code) ||
|
|
code === _constants_ts_1.CHAR_BACKWARD_SLASH;
|
|
}
|
|
exports_4("isPathSeparator", isPathSeparator);
|
|
function isWindowsDeviceRoot(code) {
|
|
return ((code >= _constants_ts_1.CHAR_LOWERCASE_A &&
|
|
code <= _constants_ts_1.CHAR_LOWERCASE_Z) ||
|
|
(code >= _constants_ts_1.CHAR_UPPERCASE_A &&
|
|
code <= _constants_ts_1.CHAR_UPPERCASE_Z));
|
|
}
|
|
exports_4("isWindowsDeviceRoot", isWindowsDeviceRoot);
|
|
// Resolves . and .. elements in a path with directory names
|
|
function normalizeString(path, allowAboveRoot, separator, isPathSeparator) {
|
|
let res = "";
|
|
let lastSegmentLength = 0;
|
|
let lastSlash = -1;
|
|
let dots = 0;
|
|
let code;
|
|
for (let i = 0, len = path.length; i <= len; ++i) {
|
|
if (i < len) {
|
|
code = path.charCodeAt(i);
|
|
} else if (isPathSeparator(code)) {
|
|
break;
|
|
} else {
|
|
code = _constants_ts_1.CHAR_FORWARD_SLASH;
|
|
}
|
|
if (isPathSeparator(code)) {
|
|
if (lastSlash === i - 1 || dots === 1) {
|
|
// NOOP
|
|
} else if (lastSlash !== i - 1 && dots === 2) {
|
|
if (
|
|
res.length < 2 ||
|
|
lastSegmentLength !== 2 ||
|
|
res.charCodeAt(res.length - 1) !== _constants_ts_1.CHAR_DOT ||
|
|
res.charCodeAt(res.length - 2) !== _constants_ts_1.CHAR_DOT
|
|
) {
|
|
if (res.length > 2) {
|
|
const lastSlashIndex = res.lastIndexOf(separator);
|
|
if (lastSlashIndex === -1) {
|
|
res = "";
|
|
lastSegmentLength = 0;
|
|
} else {
|
|
res = res.slice(0, lastSlashIndex);
|
|
lastSegmentLength = res.length - 1 -
|
|
res.lastIndexOf(separator);
|
|
}
|
|
lastSlash = i;
|
|
dots = 0;
|
|
continue;
|
|
} else if (res.length === 2 || res.length === 1) {
|
|
res = "";
|
|
lastSegmentLength = 0;
|
|
lastSlash = i;
|
|
dots = 0;
|
|
continue;
|
|
}
|
|
}
|
|
if (allowAboveRoot) {
|
|
if (res.length > 0) {
|
|
res += `${separator}..`;
|
|
} else {
|
|
res = "..";
|
|
}
|
|
lastSegmentLength = 2;
|
|
}
|
|
} else {
|
|
if (res.length > 0) {
|
|
res += separator + path.slice(lastSlash + 1, i);
|
|
} else {
|
|
res = path.slice(lastSlash + 1, i);
|
|
}
|
|
lastSegmentLength = i - lastSlash - 1;
|
|
}
|
|
lastSlash = i;
|
|
dots = 0;
|
|
} else if (code === _constants_ts_1.CHAR_DOT && dots !== -1) {
|
|
++dots;
|
|
} else {
|
|
dots = -1;
|
|
}
|
|
}
|
|
return res;
|
|
}
|
|
exports_4("normalizeString", normalizeString);
|
|
function _format(sep, pathObject) {
|
|
const dir = pathObject.dir || pathObject.root;
|
|
const base = pathObject.base ||
|
|
(pathObject.name || "") + (pathObject.ext || "");
|
|
if (!dir) {
|
|
return base;
|
|
}
|
|
if (dir === pathObject.root) {
|
|
return dir + base;
|
|
}
|
|
return dir + sep + base;
|
|
}
|
|
exports_4("_format", _format);
|
|
return {
|
|
setters: [
|
|
function (_constants_ts_1_1) {
|
|
_constants_ts_1 = _constants_ts_1_1;
|
|
},
|
|
],
|
|
execute: function () {
|
|
},
|
|
};
|
|
},
|
|
);
|
|
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
|
/** A module to print ANSI terminal colors. Inspired by chalk, kleur, and colors
|
|
* on npm.
|
|
*
|
|
* ```
|
|
* import { bgBlue, red, bold } from "https://deno.land/std/fmt/colors.ts";
|
|
* console.log(bgBlue(red(bold("Hello world!"))));
|
|
* ```
|
|
*
|
|
* This module supports `NO_COLOR` environmental variable disabling any coloring
|
|
* if `NO_COLOR` is set.
|
|
*
|
|
* This module is browser compatible. */
|
|
System.register(
|
|
"https://deno.land/std@0.56.0/fmt/colors",
|
|
[],
|
|
function (exports_5, context_5) {
|
|
"use strict";
|
|
var noColor, enabled, ANSI_PATTERN;
|
|
var __moduleName = context_5 && context_5.id;
|
|
function setColorEnabled(value) {
|
|
if (noColor) {
|
|
return;
|
|
}
|
|
enabled = value;
|
|
}
|
|
exports_5("setColorEnabled", setColorEnabled);
|
|
function getColorEnabled() {
|
|
return enabled;
|
|
}
|
|
exports_5("getColorEnabled", getColorEnabled);
|
|
function code(open, close) {
|
|
return {
|
|
open: `\x1b[${open.join(";")}m`,
|
|
close: `\x1b[${close}m`,
|
|
regexp: new RegExp(`\\x1b\\[${close}m`, "g"),
|
|
};
|
|
}
|
|
function run(str, code) {
|
|
return enabled
|
|
? `${code.open}${str.replace(code.regexp, code.open)}${code.close}`
|
|
: str;
|
|
}
|
|
function reset(str) {
|
|
return run(str, code([0], 0));
|
|
}
|
|
exports_5("reset", reset);
|
|
function bold(str) {
|
|
return run(str, code([1], 22));
|
|
}
|
|
exports_5("bold", bold);
|
|
function dim(str) {
|
|
return run(str, code([2], 22));
|
|
}
|
|
exports_5("dim", dim);
|
|
function italic(str) {
|
|
return run(str, code([3], 23));
|
|
}
|
|
exports_5("italic", italic);
|
|
function underline(str) {
|
|
return run(str, code([4], 24));
|
|
}
|
|
exports_5("underline", underline);
|
|
function inverse(str) {
|
|
return run(str, code([7], 27));
|
|
}
|
|
exports_5("inverse", inverse);
|
|
function hidden(str) {
|
|
return run(str, code([8], 28));
|
|
}
|
|
exports_5("hidden", hidden);
|
|
function strikethrough(str) {
|
|
return run(str, code([9], 29));
|
|
}
|
|
exports_5("strikethrough", strikethrough);
|
|
function black(str) {
|
|
return run(str, code([30], 39));
|
|
}
|
|
exports_5("black", black);
|
|
function red(str) {
|
|
return run(str, code([31], 39));
|
|
}
|
|
exports_5("red", red);
|
|
function green(str) {
|
|
return run(str, code([32], 39));
|
|
}
|
|
exports_5("green", green);
|
|
function yellow(str) {
|
|
return run(str, code([33], 39));
|
|
}
|
|
exports_5("yellow", yellow);
|
|
function blue(str) {
|
|
return run(str, code([34], 39));
|
|
}
|
|
exports_5("blue", blue);
|
|
function magenta(str) {
|
|
return run(str, code([35], 39));
|
|
}
|
|
exports_5("magenta", magenta);
|
|
function cyan(str) {
|
|
return run(str, code([36], 39));
|
|
}
|
|
exports_5("cyan", cyan);
|
|
function white(str) {
|
|
return run(str, code([37], 39));
|
|
}
|
|
exports_5("white", white);
|
|
function gray(str) {
|
|
return run(str, code([90], 39));
|
|
}
|
|
exports_5("gray", gray);
|
|
function bgBlack(str) {
|
|
return run(str, code([40], 49));
|
|
}
|
|
exports_5("bgBlack", bgBlack);
|
|
function bgRed(str) {
|
|
return run(str, code([41], 49));
|
|
}
|
|
exports_5("bgRed", bgRed);
|
|
function bgGreen(str) {
|
|
return run(str, code([42], 49));
|
|
}
|
|
exports_5("bgGreen", bgGreen);
|
|
function bgYellow(str) {
|
|
return run(str, code([43], 49));
|
|
}
|
|
exports_5("bgYellow", bgYellow);
|
|
function bgBlue(str) {
|
|
return run(str, code([44], 49));
|
|
}
|
|
exports_5("bgBlue", bgBlue);
|
|
function bgMagenta(str) {
|
|
return run(str, code([45], 49));
|
|
}
|
|
exports_5("bgMagenta", bgMagenta);
|
|
function bgCyan(str) {
|
|
return run(str, code([46], 49));
|
|
}
|
|
exports_5("bgCyan", bgCyan);
|
|
function bgWhite(str) {
|
|
return run(str, code([47], 49));
|
|
}
|
|
exports_5("bgWhite", bgWhite);
|
|
/* Special Color Sequences */
|
|
function clampAndTruncate(n, max = 255, min = 0) {
|
|
return Math.trunc(Math.max(Math.min(n, max), min));
|
|
}
|
|
/** Set text color using paletted 8bit colors.
|
|
* https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit */
|
|
function rgb8(str, color) {
|
|
return run(str, code([38, 5, clampAndTruncate(color)], 39));
|
|
}
|
|
exports_5("rgb8", rgb8);
|
|
/** Set background color using paletted 8bit colors.
|
|
* https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit */
|
|
function bgRgb8(str, color) {
|
|
return run(str, code([48, 5, clampAndTruncate(color)], 49));
|
|
}
|
|
exports_5("bgRgb8", bgRgb8);
|
|
/** Set text color using 24bit rgb.
|
|
* `color` can be a number in range `0x000000` to `0xffffff` or
|
|
* an `Rgb`.
|
|
*
|
|
* To produce the color magenta:
|
|
*
|
|
* rgba24("foo", 0xff00ff);
|
|
* rgba24("foo", {r: 255, g: 0, b: 255});
|
|
*/
|
|
function rgb24(str, color) {
|
|
if (typeof color === "number") {
|
|
return run(
|
|
str,
|
|
code(
|
|
[38, 2, (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff],
|
|
39,
|
|
),
|
|
);
|
|
}
|
|
return run(
|
|
str,
|
|
code([
|
|
38,
|
|
2,
|
|
clampAndTruncate(color.r),
|
|
clampAndTruncate(color.g),
|
|
clampAndTruncate(color.b),
|
|
], 39),
|
|
);
|
|
}
|
|
exports_5("rgb24", rgb24);
|
|
/** Set background color using 24bit rgb.
|
|
* `color` can be a number in range `0x000000` to `0xffffff` or
|
|
* an `Rgb`.
|
|
*
|
|
* To produce the color magenta:
|
|
*
|
|
* bgRgba24("foo", 0xff00ff);
|
|
* bgRgba24("foo", {r: 255, g: 0, b: 255});
|
|
*/
|
|
function bgRgb24(str, color) {
|
|
if (typeof color === "number") {
|
|
return run(
|
|
str,
|
|
code(
|
|
[48, 2, (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff],
|
|
49,
|
|
),
|
|
);
|
|
}
|
|
return run(
|
|
str,
|
|
code([
|
|
48,
|
|
2,
|
|
clampAndTruncate(color.r),
|
|
clampAndTruncate(color.g),
|
|
clampAndTruncate(color.b),
|
|
], 49),
|
|
);
|
|
}
|
|
exports_5("bgRgb24", bgRgb24);
|
|
function stripColor(string) {
|
|
return string.replace(ANSI_PATTERN, "");
|
|
}
|
|
exports_5("stripColor", stripColor);
|
|
return {
|
|
setters: [],
|
|
execute: function () {
|
|
noColor = globalThis.Deno?.noColor ?? true;
|
|
enabled = !noColor;
|
|
// https://github.com/chalk/ansi-regex/blob/2b56fb0c7a07108e5b54241e8faec160d393aedb/index.js
|
|
ANSI_PATTERN = new RegExp(
|
|
[
|
|
"[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)",
|
|
"(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))",
|
|
].join("|"),
|
|
"g",
|
|
);
|
|
},
|
|
};
|
|
},
|
|
);
|
|
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
|
/** This module is browser compatible. */
|
|
System.register(
|
|
"https://deno.land/std@0.56.0/testing/diff",
|
|
[],
|
|
function (exports_6, context_6) {
|
|
"use strict";
|
|
var DiffType, REMOVED, COMMON, ADDED;
|
|
var __moduleName = context_6 && context_6.id;
|
|
function createCommon(A, B, reverse) {
|
|
const common = [];
|
|
if (A.length === 0 || B.length === 0) {
|
|
return [];
|
|
}
|
|
for (let i = 0; i < Math.min(A.length, B.length); i += 1) {
|
|
if (
|
|
A[reverse ? A.length - i - 1 : i] ===
|
|
B[reverse ? B.length - i - 1 : i]
|
|
) {
|
|
common.push(A[reverse ? A.length - i - 1 : i]);
|
|
} else {
|
|
return common;
|
|
}
|
|
}
|
|
return common;
|
|
}
|
|
function diff(A, B) {
|
|
const prefixCommon = createCommon(A, B);
|
|
const suffixCommon = createCommon(
|
|
A.slice(prefixCommon.length),
|
|
B.slice(prefixCommon.length),
|
|
true,
|
|
).reverse();
|
|
A = suffixCommon.length
|
|
? A.slice(prefixCommon.length, -suffixCommon.length)
|
|
: A.slice(prefixCommon.length);
|
|
B = suffixCommon.length
|
|
? B.slice(prefixCommon.length, -suffixCommon.length)
|
|
: B.slice(prefixCommon.length);
|
|
const swapped = B.length > A.length;
|
|
[A, B] = swapped ? [B, A] : [A, B];
|
|
const M = A.length;
|
|
const N = B.length;
|
|
if (!M && !N && !suffixCommon.length && !prefixCommon.length) {
|
|
return [];
|
|
}
|
|
if (!N) {
|
|
return [
|
|
...prefixCommon.map((c) => ({ type: DiffType.common, value: c })),
|
|
...A.map((a) => ({
|
|
type: swapped ? DiffType.added : DiffType.removed,
|
|
value: a,
|
|
})),
|
|
...suffixCommon.map((c) => ({ type: DiffType.common, value: c })),
|
|
];
|
|
}
|
|
const offset = N;
|
|
const delta = M - N;
|
|
const size = M + N + 1;
|
|
const fp = new Array(size).fill({ y: -1 });
|
|
/**
|
|
* INFO:
|
|
* This buffer is used to save memory and improve performance.
|
|
* The first half is used to save route and last half is used to save diff
|
|
* type.
|
|
* This is because, when I kept new uint8array area to save type,performance
|
|
* worsened.
|
|
*/
|
|
const routes = new Uint32Array((M * N + size + 1) * 2);
|
|
const diffTypesPtrOffset = routes.length / 2;
|
|
let ptr = 0;
|
|
let p = -1;
|
|
function backTrace(A, B, current, swapped) {
|
|
const M = A.length;
|
|
const N = B.length;
|
|
const result = [];
|
|
let a = M - 1;
|
|
let b = N - 1;
|
|
let j = routes[current.id];
|
|
let type = routes[current.id + diffTypesPtrOffset];
|
|
while (true) {
|
|
if (!j && !type) {
|
|
break;
|
|
}
|
|
const prev = j;
|
|
if (type === REMOVED) {
|
|
result.unshift({
|
|
type: swapped ? DiffType.removed : DiffType.added,
|
|
value: B[b],
|
|
});
|
|
b -= 1;
|
|
} else if (type === ADDED) {
|
|
result.unshift({
|
|
type: swapped ? DiffType.added : DiffType.removed,
|
|
value: A[a],
|
|
});
|
|
a -= 1;
|
|
} else {
|
|
result.unshift({ type: DiffType.common, value: A[a] });
|
|
a -= 1;
|
|
b -= 1;
|
|
}
|
|
j = routes[prev];
|
|
type = routes[prev + diffTypesPtrOffset];
|
|
}
|
|
return result;
|
|
}
|
|
function createFP(slide, down, k, M) {
|
|
if (slide && slide.y === -1 && down && down.y === -1) {
|
|
return { y: 0, id: 0 };
|
|
}
|
|
if (
|
|
(down && down.y === -1) ||
|
|
k === M ||
|
|
(slide && slide.y) > (down && down.y) + 1
|
|
) {
|
|
const prev = slide.id;
|
|
ptr++;
|
|
routes[ptr] = prev;
|
|
routes[ptr + diffTypesPtrOffset] = ADDED;
|
|
return { y: slide.y, id: ptr };
|
|
} else {
|
|
const prev = down.id;
|
|
ptr++;
|
|
routes[ptr] = prev;
|
|
routes[ptr + diffTypesPtrOffset] = REMOVED;
|
|
return { y: down.y + 1, id: ptr };
|
|
}
|
|
}
|
|
function snake(k, slide, down, _offset, A, B) {
|
|
const M = A.length;
|
|
const N = B.length;
|
|
if (k < -N || M < k) {
|
|
return { y: -1, id: -1 };
|
|
}
|
|
const fp = createFP(slide, down, k, M);
|
|
while (fp.y + k < M && fp.y < N && A[fp.y + k] === B[fp.y]) {
|
|
const prev = fp.id;
|
|
ptr++;
|
|
fp.id = ptr;
|
|
fp.y += 1;
|
|
routes[ptr] = prev;
|
|
routes[ptr + diffTypesPtrOffset] = COMMON;
|
|
}
|
|
return fp;
|
|
}
|
|
while (fp[delta + offset].y < N) {
|
|
p = p + 1;
|
|
for (let k = -p; k < delta; ++k) {
|
|
fp[k + offset] = snake(
|
|
k,
|
|
fp[k - 1 + offset],
|
|
fp[k + 1 + offset],
|
|
offset,
|
|
A,
|
|
B,
|
|
);
|
|
}
|
|
for (let k = delta + p; k > delta; --k) {
|
|
fp[k + offset] = snake(
|
|
k,
|
|
fp[k - 1 + offset],
|
|
fp[k + 1 + offset],
|
|
offset,
|
|
A,
|
|
B,
|
|
);
|
|
}
|
|
fp[delta + offset] = snake(
|
|
delta,
|
|
fp[delta - 1 + offset],
|
|
fp[delta + 1 + offset],
|
|
offset,
|
|
A,
|
|
B,
|
|
);
|
|
}
|
|
return [
|
|
...prefixCommon.map((c) => ({ type: DiffType.common, value: c })),
|
|
...backTrace(A, B, fp[delta + offset], swapped),
|
|
...suffixCommon.map((c) => ({ type: DiffType.common, value: c })),
|
|
];
|
|
}
|
|
exports_6("default", diff);
|
|
return {
|
|
setters: [],
|
|
execute: function () {
|
|
(function (DiffType) {
|
|
DiffType["removed"] = "removed";
|
|
DiffType["common"] = "common";
|
|
DiffType["added"] = "added";
|
|
})(DiffType || (DiffType = {}));
|
|
exports_6("DiffType", DiffType);
|
|
REMOVED = 1;
|
|
COMMON = 2;
|
|
ADDED = 3;
|
|
},
|
|
};
|
|
},
|
|
);
|
|
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
|
/** This module is browser compatible. Do not rely on good formatting of values
|
|
* for AssertionError messages in browsers. */
|
|
System.register(
|
|
"https://deno.land/std@0.56.0/testing/asserts",
|
|
[
|
|
"https://deno.land/std@0.56.0/fmt/colors",
|
|
"https://deno.land/std@0.56.0/testing/diff",
|
|
],
|
|
function (exports_7, context_7) {
|
|
"use strict";
|
|
var colors_ts_1, diff_ts_1, CAN_NOT_DISPLAY, AssertionError;
|
|
var __moduleName = context_7 && context_7.id;
|
|
function format(v) {
|
|
let string = globalThis.Deno ? Deno.inspect(v) : String(v);
|
|
if (typeof v == "string") {
|
|
string = `"${string.replace(/(?=["\\])/g, "\\")}"`;
|
|
}
|
|
return string;
|
|
}
|
|
function createColor(diffType) {
|
|
switch (diffType) {
|
|
case diff_ts_1.DiffType.added:
|
|
return (s) => colors_ts_1.green(colors_ts_1.bold(s));
|
|
case diff_ts_1.DiffType.removed:
|
|
return (s) => colors_ts_1.red(colors_ts_1.bold(s));
|
|
default:
|
|
return colors_ts_1.white;
|
|
}
|
|
}
|
|
function createSign(diffType) {
|
|
switch (diffType) {
|
|
case diff_ts_1.DiffType.added:
|
|
return "+ ";
|
|
case diff_ts_1.DiffType.removed:
|
|
return "- ";
|
|
default:
|
|
return " ";
|
|
}
|
|
}
|
|
function buildMessage(diffResult) {
|
|
const messages = [];
|
|
messages.push("");
|
|
messages.push("");
|
|
messages.push(
|
|
` ${colors_ts_1.gray(colors_ts_1.bold("[Diff]"))} ${
|
|
colors_ts_1.red(colors_ts_1.bold("Actual"))
|
|
} / ${colors_ts_1.green(colors_ts_1.bold("Expected"))}`,
|
|
);
|
|
messages.push("");
|
|
messages.push("");
|
|
diffResult.forEach((result) => {
|
|
const c = createColor(result.type);
|
|
messages.push(c(`${createSign(result.type)}${result.value}`));
|
|
});
|
|
messages.push("");
|
|
return messages;
|
|
}
|
|
function isKeyedCollection(x) {
|
|
return [Symbol.iterator, "size"].every((k) => k in x);
|
|
}
|
|
function equal(c, d) {
|
|
const seen = new Map();
|
|
return (function compare(a, b) {
|
|
// Have to render RegExp & Date for string comparison
|
|
// unless it's mistreated as object
|
|
if (
|
|
a &&
|
|
b &&
|
|
((a instanceof RegExp && b instanceof RegExp) ||
|
|
(a instanceof Date && b instanceof Date))
|
|
) {
|
|
return String(a) === String(b);
|
|
}
|
|
if (Object.is(a, b)) {
|
|
return true;
|
|
}
|
|
if (a && typeof a === "object" && b && typeof b === "object") {
|
|
if (seen.get(a) === b) {
|
|
return true;
|
|
}
|
|
if (Object.keys(a || {}).length !== Object.keys(b || {}).length) {
|
|
return false;
|
|
}
|
|
if (isKeyedCollection(a) && isKeyedCollection(b)) {
|
|
if (a.size !== b.size) {
|
|
return false;
|
|
}
|
|
let unmatchedEntries = a.size;
|
|
for (const [aKey, aValue] of a.entries()) {
|
|
for (const [bKey, bValue] of b.entries()) {
|
|
/* Given that Map keys can be references, we need
|
|
* to ensure that they are also deeply equal */
|
|
if (
|
|
(aKey === aValue && bKey === bValue && compare(aKey, bKey)) ||
|
|
(compare(aKey, bKey) && compare(aValue, bValue))
|
|
) {
|
|
unmatchedEntries--;
|
|
}
|
|
}
|
|
}
|
|
return unmatchedEntries === 0;
|
|
}
|
|
const merged = { ...a, ...b };
|
|
for (const key in merged) {
|
|
if (!compare(a && a[key], b && b[key])) {
|
|
return false;
|
|
}
|
|
}
|
|
seen.set(a, b);
|
|
return true;
|
|
}
|
|
return false;
|
|
})(c, d);
|
|
}
|
|
exports_7("equal", equal);
|
|
/** Make an assertion, if not `true`, then throw. */
|
|
function assert(expr, msg = "") {
|
|
if (!expr) {
|
|
throw new AssertionError(msg);
|
|
}
|
|
}
|
|
exports_7("assert", assert);
|
|
/**
|
|
* Make an assertion that `actual` and `expected` are equal, deeply. If not
|
|
* deeply equal, then throw.
|
|
*/
|
|
function assertEquals(actual, expected, msg) {
|
|
if (equal(actual, expected)) {
|
|
return;
|
|
}
|
|
let message = "";
|
|
const actualString = format(actual);
|
|
const expectedString = format(expected);
|
|
try {
|
|
const diffResult = diff_ts_1.default(
|
|
actualString.split("\n"),
|
|
expectedString.split("\n"),
|
|
);
|
|
const diffMsg = buildMessage(diffResult).join("\n");
|
|
message = `Values are not equal:\n${diffMsg}`;
|
|
} catch (e) {
|
|
message = `\n${colors_ts_1.red(CAN_NOT_DISPLAY)} + \n\n`;
|
|
}
|
|
if (msg) {
|
|
message = msg;
|
|
}
|
|
throw new AssertionError(message);
|
|
}
|
|
exports_7("assertEquals", assertEquals);
|
|
/**
|
|
* Make an assertion that `actual` and `expected` are not equal, deeply.
|
|
* If not then throw.
|
|
*/
|
|
function assertNotEquals(actual, expected, msg) {
|
|
if (!equal(actual, expected)) {
|
|
return;
|
|
}
|
|
let actualString;
|
|
let expectedString;
|
|
try {
|
|
actualString = String(actual);
|
|
} catch (e) {
|
|
actualString = "[Cannot display]";
|
|
}
|
|
try {
|
|
expectedString = String(expected);
|
|
} catch (e) {
|
|
expectedString = "[Cannot display]";
|
|
}
|
|
if (!msg) {
|
|
msg = `actual: ${actualString} expected: ${expectedString}`;
|
|
}
|
|
throw new AssertionError(msg);
|
|
}
|
|
exports_7("assertNotEquals", assertNotEquals);
|
|
/**
|
|
* Make an assertion that `actual` and `expected` are strictly equal. If
|
|
* not then throw.
|
|
*/
|
|
function assertStrictEq(actual, expected, msg) {
|
|
if (actual === expected) {
|
|
return;
|
|
}
|
|
let message;
|
|
if (msg) {
|
|
message = msg;
|
|
} else {
|
|
const actualString = format(actual);
|
|
const expectedString = format(expected);
|
|
if (actualString === expectedString) {
|
|
const withOffset = actualString
|
|
.split("\n")
|
|
.map((l) => ` ${l}`)
|
|
.join("\n");
|
|
message =
|
|
`Values have the same structure but are not reference-equal:\n\n${
|
|
colors_ts_1.red(withOffset)
|
|
}\n`;
|
|
} else {
|
|
try {
|
|
const diffResult = diff_ts_1.default(
|
|
actualString.split("\n"),
|
|
expectedString.split("\n"),
|
|
);
|
|
const diffMsg = buildMessage(diffResult).join("\n");
|
|
message = `Values are not strictly equal:\n${diffMsg}`;
|
|
} catch (e) {
|
|
message = `\n${colors_ts_1.red(CAN_NOT_DISPLAY)} + \n\n`;
|
|
}
|
|
}
|
|
}
|
|
throw new AssertionError(message);
|
|
}
|
|
exports_7("assertStrictEq", assertStrictEq);
|
|
/**
|
|
* Make an assertion that actual contains expected. If not
|
|
* then thrown.
|
|
*/
|
|
function assertStrContains(actual, expected, msg) {
|
|
if (!actual.includes(expected)) {
|
|
if (!msg) {
|
|
msg = `actual: "${actual}" expected to contain: "${expected}"`;
|
|
}
|
|
throw new AssertionError(msg);
|
|
}
|
|
}
|
|
exports_7("assertStrContains", assertStrContains);
|
|
/**
|
|
* Make an assertion that `actual` contains the `expected` values
|
|
* If not then thrown.
|
|
*/
|
|
function assertArrayContains(actual, expected, msg) {
|
|
const missing = [];
|
|
for (let i = 0; i < expected.length; i++) {
|
|
let found = false;
|
|
for (let j = 0; j < actual.length; j++) {
|
|
if (equal(expected[i], actual[j])) {
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!found) {
|
|
missing.push(expected[i]);
|
|
}
|
|
}
|
|
if (missing.length === 0) {
|
|
return;
|
|
}
|
|
if (!msg) {
|
|
msg = `actual: "${format(actual)}" expected to contain: "${
|
|
format(expected)
|
|
}"\nmissing: ${format(missing)}`;
|
|
}
|
|
throw new AssertionError(msg);
|
|
}
|
|
exports_7("assertArrayContains", assertArrayContains);
|
|
/**
|
|
* Make an assertion that `actual` match RegExp `expected`. If not
|
|
* then thrown
|
|
*/
|
|
function assertMatch(actual, expected, msg) {
|
|
if (!expected.test(actual)) {
|
|
if (!msg) {
|
|
msg = `actual: "${actual}" expected to match: "${expected}"`;
|
|
}
|
|
throw new AssertionError(msg);
|
|
}
|
|
}
|
|
exports_7("assertMatch", assertMatch);
|
|
/**
|
|
* Forcefully throws a failed assertion
|
|
*/
|
|
function fail(msg) {
|
|
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
assert(false, `Failed assertion${msg ? `: ${msg}` : "."}`);
|
|
}
|
|
exports_7("fail", fail);
|
|
/** Executes a function, expecting it to throw. If it does not, then it
|
|
* throws. An error class and a string that should be included in the
|
|
* error message can also be asserted.
|
|
*/
|
|
function assertThrows(fn, ErrorClass, msgIncludes = "", msg) {
|
|
let doesThrow = false;
|
|
let error = null;
|
|
try {
|
|
fn();
|
|
} catch (e) {
|
|
if (
|
|
ErrorClass && !(Object.getPrototypeOf(e) === ErrorClass.prototype)
|
|
) {
|
|
msg =
|
|
`Expected error to be instance of "${ErrorClass.name}", but was "${e.constructor.name}"${
|
|
msg ? `: ${msg}` : "."
|
|
}`;
|
|
throw new AssertionError(msg);
|
|
}
|
|
if (
|
|
msgIncludes &&
|
|
!colors_ts_1.stripColor(e.message).includes(
|
|
colors_ts_1.stripColor(msgIncludes),
|
|
)
|
|
) {
|
|
msg =
|
|
`Expected error message to include "${msgIncludes}", but got "${e.message}"${
|
|
msg ? `: ${msg}` : "."
|
|
}`;
|
|
throw new AssertionError(msg);
|
|
}
|
|
doesThrow = true;
|
|
error = e;
|
|
}
|
|
if (!doesThrow) {
|
|
msg = `Expected function to throw${msg ? `: ${msg}` : "."}`;
|
|
throw new AssertionError(msg);
|
|
}
|
|
return error;
|
|
}
|
|
exports_7("assertThrows", assertThrows);
|
|
async function assertThrowsAsync(fn, ErrorClass, msgIncludes = "", msg) {
|
|
let doesThrow = false;
|
|
let error = null;
|
|
try {
|
|
await fn();
|
|
} catch (e) {
|
|
if (
|
|
ErrorClass && !(Object.getPrototypeOf(e) === ErrorClass.prototype)
|
|
) {
|
|
msg =
|
|
`Expected error to be instance of "${ErrorClass.name}", but got "${e.name}"${
|
|
msg ? `: ${msg}` : "."
|
|
}`;
|
|
throw new AssertionError(msg);
|
|
}
|
|
if (
|
|
msgIncludes &&
|
|
!colors_ts_1.stripColor(e.message).includes(
|
|
colors_ts_1.stripColor(msgIncludes),
|
|
)
|
|
) {
|
|
msg =
|
|
`Expected error message to include "${msgIncludes}", but got "${e.message}"${
|
|
msg ? `: ${msg}` : "."
|
|
}`;
|
|
throw new AssertionError(msg);
|
|
}
|
|
doesThrow = true;
|
|
error = e;
|
|
}
|
|
if (!doesThrow) {
|
|
msg = `Expected function to throw${msg ? `: ${msg}` : "."}`;
|
|
throw new AssertionError(msg);
|
|
}
|
|
return error;
|
|
}
|
|
exports_7("assertThrowsAsync", assertThrowsAsync);
|
|
/** Use this to stub out methods that will throw when invoked. */
|
|
function unimplemented(msg) {
|
|
throw new AssertionError(msg || "unimplemented");
|
|
}
|
|
exports_7("unimplemented", unimplemented);
|
|
/** Use this to assert unreachable code. */
|
|
function unreachable() {
|
|
throw new AssertionError("unreachable");
|
|
}
|
|
exports_7("unreachable", unreachable);
|
|
return {
|
|
setters: [
|
|
function (colors_ts_1_1) {
|
|
colors_ts_1 = colors_ts_1_1;
|
|
},
|
|
function (diff_ts_1_1) {
|
|
diff_ts_1 = diff_ts_1_1;
|
|
},
|
|
],
|
|
execute: function () {
|
|
CAN_NOT_DISPLAY = "[Cannot display]";
|
|
AssertionError = class AssertionError extends Error {
|
|
constructor(message) {
|
|
super(message);
|
|
this.name = "AssertionError";
|
|
}
|
|
};
|
|
exports_7("AssertionError", AssertionError);
|
|
},
|
|
};
|
|
},
|
|
);
|
|
// Copyright the Browserify authors. MIT License.
|
|
// Ported from https://github.com/browserify/path-browserify/
|
|
/** This module is browser compatible. */
|
|
System.register(
|
|
"https://deno.land/std@0.56.0/path/win32",
|
|
[
|
|
"https://deno.land/std@0.56.0/path/_constants",
|
|
"https://deno.land/std@0.56.0/path/_util",
|
|
"https://deno.land/std@0.56.0/testing/asserts",
|
|
],
|
|
function (exports_8, context_8) {
|
|
"use strict";
|
|
var _constants_ts_2, _util_ts_1, asserts_ts_1, sep, delimiter;
|
|
var __moduleName = context_8 && context_8.id;
|
|
function resolve(...pathSegments) {
|
|
let resolvedDevice = "";
|
|
let resolvedTail = "";
|
|
let resolvedAbsolute = false;
|
|
for (let i = pathSegments.length - 1; i >= -1; i--) {
|
|
let path;
|
|
if (i >= 0) {
|
|
path = pathSegments[i];
|
|
} else if (!resolvedDevice) {
|
|
if (globalThis.Deno == null) {
|
|
throw new TypeError(
|
|
"Resolved a drive-letter-less path without a CWD.",
|
|
);
|
|
}
|
|
path = Deno.cwd();
|
|
} else {
|
|
if (globalThis.Deno == null) {
|
|
throw new TypeError("Resolved a relative path without a CWD.");
|
|
}
|
|
// Windows has the concept of drive-specific current working
|
|
// directories. If we've resolved a drive letter but not yet an
|
|
// absolute path, get cwd for that drive, or the process cwd if
|
|
// the drive cwd is not available. We're sure the device is not
|
|
// a UNC path at this points, because UNC paths are always absolute.
|
|
path = Deno.env.get(`=${resolvedDevice}`) || Deno.cwd();
|
|
// Verify that a cwd was found and that it actually points
|
|
// to our drive. If not, default to the drive's root.
|
|
if (
|
|
path === undefined ||
|
|
path.slice(0, 3).toLowerCase() !==
|
|
`${resolvedDevice.toLowerCase()}\\`
|
|
) {
|
|
path = `${resolvedDevice}\\`;
|
|
}
|
|
}
|
|
_util_ts_1.assertPath(path);
|
|
const len = path.length;
|
|
// Skip empty entries
|
|
if (len === 0) {
|
|
continue;
|
|
}
|
|
let rootEnd = 0;
|
|
let device = "";
|
|
let isAbsolute = false;
|
|
const code = path.charCodeAt(0);
|
|
// Try to match a root
|
|
if (len > 1) {
|
|
if (_util_ts_1.isPathSeparator(code)) {
|
|
// Possible UNC root
|
|
// If we started with a separator, we know we at least have an
|
|
// absolute path of some kind (UNC or otherwise)
|
|
isAbsolute = true;
|
|
if (_util_ts_1.isPathSeparator(path.charCodeAt(1))) {
|
|
// Matched double path separator at beginning
|
|
let j = 2;
|
|
let last = j;
|
|
// Match 1 or more non-path separators
|
|
for (; j < len; ++j) {
|
|
if (_util_ts_1.isPathSeparator(path.charCodeAt(j))) {
|
|
break;
|
|
}
|
|
}
|
|
if (j < len && j !== last) {
|
|
const firstPart = path.slice(last, j);
|
|
// Matched!
|
|
last = j;
|
|
// Match 1 or more path separators
|
|
for (; j < len; ++j) {
|
|
if (!_util_ts_1.isPathSeparator(path.charCodeAt(j))) {
|
|
break;
|
|
}
|
|
}
|
|
if (j < len && j !== last) {
|
|
// Matched!
|
|
last = j;
|
|
// Match 1 or more non-path separators
|
|
for (; j < len; ++j) {
|
|
if (_util_ts_1.isPathSeparator(path.charCodeAt(j))) {
|
|
break;
|
|
}
|
|
}
|
|
if (j === len) {
|
|
// We matched a UNC root only
|
|
device = `\\\\${firstPart}\\${path.slice(last)}`;
|
|
rootEnd = j;
|
|
} else if (j !== last) {
|
|
// We matched a UNC root with leftovers
|
|
device = `\\\\${firstPart}\\${path.slice(last, j)}`;
|
|
rootEnd = j;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
rootEnd = 1;
|
|
}
|
|
} else if (_util_ts_1.isWindowsDeviceRoot(code)) {
|
|
// Possible device root
|
|
if (path.charCodeAt(1) === _constants_ts_2.CHAR_COLON) {
|
|
device = path.slice(0, 2);
|
|
rootEnd = 2;
|
|
if (len > 2) {
|
|
if (_util_ts_1.isPathSeparator(path.charCodeAt(2))) {
|
|
// Treat separator following drive name as an absolute path
|
|
// indicator
|
|
isAbsolute = true;
|
|
rootEnd = 3;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else if (_util_ts_1.isPathSeparator(code)) {
|
|
// `path` contains just a path separator
|
|
rootEnd = 1;
|
|
isAbsolute = true;
|
|
}
|
|
if (
|
|
device.length > 0 &&
|
|
resolvedDevice.length > 0 &&
|
|
device.toLowerCase() !== resolvedDevice.toLowerCase()
|
|
) {
|
|
// This path points to another device so it is not applicable
|
|
continue;
|
|
}
|
|
if (resolvedDevice.length === 0 && device.length > 0) {
|
|
resolvedDevice = device;
|
|
}
|
|
if (!resolvedAbsolute) {
|
|
resolvedTail = `${path.slice(rootEnd)}\\${resolvedTail}`;
|
|
resolvedAbsolute = isAbsolute;
|
|
}
|
|
if (resolvedAbsolute && resolvedDevice.length > 0) {
|
|
break;
|
|
}
|
|
}
|
|
// At this point the path should be resolved to a full absolute path,
|
|
// but handle relative paths to be safe (might happen when process.cwd()
|
|
// fails)
|
|
// Normalize the tail path
|
|
resolvedTail = _util_ts_1.normalizeString(
|
|
resolvedTail,
|
|
!resolvedAbsolute,
|
|
"\\",
|
|
_util_ts_1.isPathSeparator,
|
|
);
|
|
return resolvedDevice + (resolvedAbsolute ? "\\" : "") + resolvedTail ||
|
|
".";
|
|
}
|
|
exports_8("resolve", resolve);
|
|
function normalize(path) {
|
|
_util_ts_1.assertPath(path);
|
|
const len = path.length;
|
|
if (len === 0) {
|
|
return ".";
|
|
}
|
|
let rootEnd = 0;
|
|
let device;
|
|
let isAbsolute = false;
|
|
const code = path.charCodeAt(0);
|
|
// Try to match a root
|
|
if (len > 1) {
|
|
if (_util_ts_1.isPathSeparator(code)) {
|
|
// Possible UNC root
|
|
// If we started with a separator, we know we at least have an absolute
|
|
// path of some kind (UNC or otherwise)
|
|
isAbsolute = true;
|
|
if (_util_ts_1.isPathSeparator(path.charCodeAt(1))) {
|
|
// Matched double path separator at beginning
|
|
let j = 2;
|
|
let last = j;
|
|
// Match 1 or more non-path separators
|
|
for (; j < len; ++j) {
|
|
if (_util_ts_1.isPathSeparator(path.charCodeAt(j))) {
|
|
break;
|
|
}
|
|
}
|
|
if (j < len && j !== last) {
|
|
const firstPart = path.slice(last, j);
|
|
// Matched!
|
|
last = j;
|
|
// Match 1 or more path separators
|
|
for (; j < len; ++j) {
|
|
if (!_util_ts_1.isPathSeparator(path.charCodeAt(j))) {
|
|
break;
|
|
}
|
|
}
|
|
if (j < len && j !== last) {
|
|
// Matched!
|
|
last = j;
|
|
// Match 1 or more non-path separators
|
|
for (; j < len; ++j) {
|
|
if (_util_ts_1.isPathSeparator(path.charCodeAt(j))) {
|
|
break;
|
|
}
|
|
}
|
|
if (j === len) {
|
|
// We matched a UNC root only
|
|
// Return the normalized version of the UNC root since there
|
|
// is nothing left to process
|
|
return `\\\\${firstPart}\\${path.slice(last)}\\`;
|
|
} else if (j !== last) {
|
|
// We matched a UNC root with leftovers
|
|
device = `\\\\${firstPart}\\${path.slice(last, j)}`;
|
|
rootEnd = j;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
rootEnd = 1;
|
|
}
|
|
} else if (_util_ts_1.isWindowsDeviceRoot(code)) {
|
|
// Possible device root
|
|
if (path.charCodeAt(1) === _constants_ts_2.CHAR_COLON) {
|
|
device = path.slice(0, 2);
|
|
rootEnd = 2;
|
|
if (len > 2) {
|
|
if (_util_ts_1.isPathSeparator(path.charCodeAt(2))) {
|
|
// Treat separator following drive name as an absolute path
|
|
// indicator
|
|
isAbsolute = true;
|
|
rootEnd = 3;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else if (_util_ts_1.isPathSeparator(code)) {
|
|
// `path` contains just a path separator, exit early to avoid unnecessary
|
|
// work
|
|
return "\\";
|
|
}
|
|
let tail;
|
|
if (rootEnd < len) {
|
|
tail = _util_ts_1.normalizeString(
|
|
path.slice(rootEnd),
|
|
!isAbsolute,
|
|
"\\",
|
|
_util_ts_1.isPathSeparator,
|
|
);
|
|
} else {
|
|
tail = "";
|
|
}
|
|
if (tail.length === 0 && !isAbsolute) {
|
|
tail = ".";
|
|
}
|
|
if (
|
|
tail.length > 0 &&
|
|
_util_ts_1.isPathSeparator(path.charCodeAt(len - 1))
|
|
) {
|
|
tail += "\\";
|
|
}
|
|
if (device === undefined) {
|
|
if (isAbsolute) {
|
|
if (tail.length > 0) {
|
|
return `\\${tail}`;
|
|
} else {
|
|
return "\\";
|
|
}
|
|
} else if (tail.length > 0) {
|
|
return tail;
|
|
} else {
|
|
return "";
|
|
}
|
|
} else if (isAbsolute) {
|
|
if (tail.length > 0) {
|
|
return `${device}\\${tail}`;
|
|
} else {
|
|
return `${device}\\`;
|
|
}
|
|
} else if (tail.length > 0) {
|
|
return device + tail;
|
|
} else {
|
|
return device;
|
|
}
|
|
}
|
|
exports_8("normalize", normalize);
|
|
function isAbsolute(path) {
|
|
_util_ts_1.assertPath(path);
|
|
const len = path.length;
|
|
if (len === 0) {
|
|
return false;
|
|
}
|
|
const code = path.charCodeAt(0);
|
|
if (_util_ts_1.isPathSeparator(code)) {
|
|
return true;
|
|
} else if (_util_ts_1.isWindowsDeviceRoot(code)) {
|
|
// Possible device root
|
|
if (len > 2 && path.charCodeAt(1) === _constants_ts_2.CHAR_COLON) {
|
|
if (_util_ts_1.isPathSeparator(path.charCodeAt(2))) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
exports_8("isAbsolute", isAbsolute);
|
|
function join(...paths) {
|
|
const pathsCount = paths.length;
|
|
if (pathsCount === 0) {
|
|
return ".";
|
|
}
|
|
let joined;
|
|
let firstPart = null;
|
|
for (let i = 0; i < pathsCount; ++i) {
|
|
const path = paths[i];
|
|
_util_ts_1.assertPath(path);
|
|
if (path.length > 0) {
|
|
if (joined === undefined) {
|
|
joined = firstPart = path;
|
|
} else {
|
|
joined += `\\${path}`;
|
|
}
|
|
}
|
|
}
|
|
if (joined === undefined) {
|
|
return ".";
|
|
}
|
|
// Make sure that the joined path doesn't start with two slashes, because
|
|
// normalize() will mistake it for an UNC path then.
|
|
//
|
|
// This step is skipped when it is very clear that the user actually
|
|
// intended to point at an UNC path. This is assumed when the first
|
|
// non-empty string arguments starts with exactly two slashes followed by
|
|
// at least one more non-slash character.
|
|
//
|
|
// Note that for normalize() to treat a path as an UNC path it needs to
|
|
// have at least 2 components, so we don't filter for that here.
|
|
// This means that the user can use join to construct UNC paths from
|
|
// a server name and a share name; for example:
|
|
// path.join('//server', 'share') -> '\\\\server\\share\\')
|
|
let needsReplace = true;
|
|
let slashCount = 0;
|
|
asserts_ts_1.assert(firstPart != null);
|
|
if (_util_ts_1.isPathSeparator(firstPart.charCodeAt(0))) {
|
|
++slashCount;
|
|
const firstLen = firstPart.length;
|
|
if (firstLen > 1) {
|
|
if (_util_ts_1.isPathSeparator(firstPart.charCodeAt(1))) {
|
|
++slashCount;
|
|
if (firstLen > 2) {
|
|
if (_util_ts_1.isPathSeparator(firstPart.charCodeAt(2))) {
|
|
++slashCount;
|
|
} else {
|
|
// We matched a UNC path in the first part
|
|
needsReplace = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (needsReplace) {
|
|
// Find any more consecutive slashes we need to replace
|
|
for (; slashCount < joined.length; ++slashCount) {
|
|
if (!_util_ts_1.isPathSeparator(joined.charCodeAt(slashCount))) {
|
|
break;
|
|
}
|
|
}
|
|
// Replace the slashes if needed
|
|
if (slashCount >= 2) {
|
|
joined = `\\${joined.slice(slashCount)}`;
|
|
}
|
|
}
|
|
return normalize(joined);
|
|
}
|
|
exports_8("join", join);
|
|
// It will solve the relative path from `from` to `to`, for instance:
|
|
// from = 'C:\\orandea\\test\\aaa'
|
|
// to = 'C:\\orandea\\impl\\bbb'
|
|
// The output of the function should be: '..\\..\\impl\\bbb'
|
|
function relative(from, to) {
|
|
_util_ts_1.assertPath(from);
|
|
_util_ts_1.assertPath(to);
|
|
if (from === to) {
|
|
return "";
|
|
}
|
|
const fromOrig = resolve(from);
|
|
const toOrig = resolve(to);
|
|
if (fromOrig === toOrig) {
|
|
return "";
|
|
}
|
|
from = fromOrig.toLowerCase();
|
|
to = toOrig.toLowerCase();
|
|
if (from === to) {
|
|
return "";
|
|
}
|
|
// Trim any leading backslashes
|
|
let fromStart = 0;
|
|
let fromEnd = from.length;
|
|
for (; fromStart < fromEnd; ++fromStart) {
|
|
if (
|
|
from.charCodeAt(fromStart) !== _constants_ts_2.CHAR_BACKWARD_SLASH
|
|
) {
|
|
break;
|
|
}
|
|
}
|
|
// Trim trailing backslashes (applicable to UNC paths only)
|
|
for (; fromEnd - 1 > fromStart; --fromEnd) {
|
|
if (
|
|
from.charCodeAt(fromEnd - 1) !== _constants_ts_2.CHAR_BACKWARD_SLASH
|
|
) {
|
|
break;
|
|
}
|
|
}
|
|
const fromLen = fromEnd - fromStart;
|
|
// Trim any leading backslashes
|
|
let toStart = 0;
|
|
let toEnd = to.length;
|
|
for (; toStart < toEnd; ++toStart) {
|
|
if (to.charCodeAt(toStart) !== _constants_ts_2.CHAR_BACKWARD_SLASH) {
|
|
break;
|
|
}
|
|
}
|
|
// Trim trailing backslashes (applicable to UNC paths only)
|
|
for (; toEnd - 1 > toStart; --toEnd) {
|
|
if (to.charCodeAt(toEnd - 1) !== _constants_ts_2.CHAR_BACKWARD_SLASH) {
|
|
break;
|
|
}
|
|
}
|
|
const toLen = toEnd - toStart;
|
|
// Compare paths to find the longest common path from root
|
|
const length = fromLen < toLen ? fromLen : toLen;
|
|
let lastCommonSep = -1;
|
|
let i = 0;
|
|
for (; i <= length; ++i) {
|
|
if (i === length) {
|
|
if (toLen > length) {
|
|
if (
|
|
to.charCodeAt(toStart + i) === _constants_ts_2.CHAR_BACKWARD_SLASH
|
|
) {
|
|
// We get here if `from` is the exact base path for `to`.
|
|
// For example: from='C:\\foo\\bar'; to='C:\\foo\\bar\\baz'
|
|
return toOrig.slice(toStart + i + 1);
|
|
} else if (i === 2) {
|
|
// We get here if `from` is the device root.
|
|
// For example: from='C:\\'; to='C:\\foo'
|
|
return toOrig.slice(toStart + i);
|
|
}
|
|
}
|
|
if (fromLen > length) {
|
|
if (
|
|
from.charCodeAt(fromStart + i) ===
|
|
_constants_ts_2.CHAR_BACKWARD_SLASH
|
|
) {
|
|
// We get here if `to` is the exact base path for `from`.
|
|
// For example: from='C:\\foo\\bar'; to='C:\\foo'
|
|
lastCommonSep = i;
|
|
} else if (i === 2) {
|
|
// We get here if `to` is the device root.
|
|
// For example: from='C:\\foo\\bar'; to='C:\\'
|
|
lastCommonSep = 3;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
const fromCode = from.charCodeAt(fromStart + i);
|
|
const toCode = to.charCodeAt(toStart + i);
|
|
if (fromCode !== toCode) {
|
|
break;
|
|
} else if (fromCode === _constants_ts_2.CHAR_BACKWARD_SLASH) {
|
|
lastCommonSep = i;
|
|
}
|
|
}
|
|
// We found a mismatch before the first common path separator was seen, so
|
|
// return the original `to`.
|
|
if (i !== length && lastCommonSep === -1) {
|
|
return toOrig;
|
|
}
|
|
let out = "";
|
|
if (lastCommonSep === -1) {
|
|
lastCommonSep = 0;
|
|
}
|
|
// Generate the relative path based on the path difference between `to` and
|
|
// `from`
|
|
for (i = fromStart + lastCommonSep + 1; i <= fromEnd; ++i) {
|
|
if (
|
|
i === fromEnd ||
|
|
from.charCodeAt(i) === _constants_ts_2.CHAR_BACKWARD_SLASH
|
|
) {
|
|
if (out.length === 0) {
|
|
out += "..";
|
|
} else {
|
|
out += "\\..";
|
|
}
|
|
}
|
|
}
|
|
// Lastly, append the rest of the destination (`to`) path that comes after
|
|
// the common path parts
|
|
if (out.length > 0) {
|
|
return out + toOrig.slice(toStart + lastCommonSep, toEnd);
|
|
} else {
|
|
toStart += lastCommonSep;
|
|
if (
|
|
toOrig.charCodeAt(toStart) === _constants_ts_2.CHAR_BACKWARD_SLASH
|
|
) {
|
|
++toStart;
|
|
}
|
|
return toOrig.slice(toStart, toEnd);
|
|
}
|
|
}
|
|
exports_8("relative", relative);
|
|
function toNamespacedPath(path) {
|
|
// Note: this will *probably* throw somewhere.
|
|
if (typeof path !== "string") {
|
|
return path;
|
|
}
|
|
if (path.length === 0) {
|
|
return "";
|
|
}
|
|
const resolvedPath = resolve(path);
|
|
if (resolvedPath.length >= 3) {
|
|
if (
|
|
resolvedPath.charCodeAt(0) === _constants_ts_2.CHAR_BACKWARD_SLASH
|
|
) {
|
|
// Possible UNC root
|
|
if (
|
|
resolvedPath.charCodeAt(1) === _constants_ts_2.CHAR_BACKWARD_SLASH
|
|
) {
|
|
const code = resolvedPath.charCodeAt(2);
|
|
if (
|
|
code !== _constants_ts_2.CHAR_QUESTION_MARK &&
|
|
code !== _constants_ts_2.CHAR_DOT
|
|
) {
|
|
// Matched non-long UNC root, convert the path to a long UNC path
|
|
return `\\\\?\\UNC\\${resolvedPath.slice(2)}`;
|
|
}
|
|
}
|
|
} else if (_util_ts_1.isWindowsDeviceRoot(resolvedPath.charCodeAt(0))) {
|
|
// Possible device root
|
|
if (
|
|
resolvedPath.charCodeAt(1) === _constants_ts_2.CHAR_COLON &&
|
|
resolvedPath.charCodeAt(2) === _constants_ts_2.CHAR_BACKWARD_SLASH
|
|
) {
|
|
// Matched device root, convert the path to a long UNC path
|
|
return `\\\\?\\${resolvedPath}`;
|
|
}
|
|
}
|
|
}
|
|
return path;
|
|
}
|
|
exports_8("toNamespacedPath", toNamespacedPath);
|
|
function dirname(path) {
|
|
_util_ts_1.assertPath(path);
|
|
const len = path.length;
|
|
if (len === 0) {
|
|
return ".";
|
|
}
|
|
let rootEnd = -1;
|
|
let end = -1;
|
|
let matchedSlash = true;
|
|
let offset = 0;
|
|
const code = path.charCodeAt(0);
|
|
// Try to match a root
|
|
if (len > 1) {
|
|
if (_util_ts_1.isPathSeparator(code)) {
|
|
// Possible UNC root
|
|
rootEnd = offset = 1;
|
|
if (_util_ts_1.isPathSeparator(path.charCodeAt(1))) {
|
|
// Matched double path separator at beginning
|
|
let j = 2;
|
|
let last = j;
|
|
// Match 1 or more non-path separators
|
|
for (; j < len; ++j) {
|
|
if (_util_ts_1.isPathSeparator(path.charCodeAt(j))) {
|
|
break;
|
|
}
|
|
}
|
|
if (j < len && j !== last) {
|
|
// Matched!
|
|
last = j;
|
|
// Match 1 or more path separators
|
|
for (; j < len; ++j) {
|
|
if (!_util_ts_1.isPathSeparator(path.charCodeAt(j))) {
|
|
break;
|
|
}
|
|
}
|
|
if (j < len && j !== last) {
|
|
// Matched!
|
|
last = j;
|
|
// Match 1 or more non-path separators
|
|
for (; j < len; ++j) {
|
|
if (_util_ts_1.isPathSeparator(path.charCodeAt(j))) {
|
|
break;
|
|
}
|
|
}
|
|
if (j === len) {
|
|
// We matched a UNC root only
|
|
return path;
|
|
}
|
|
if (j !== last) {
|
|
// We matched a UNC root with leftovers
|
|
// Offset by 1 to include the separator after the UNC root to
|
|
// treat it as a "normal root" on top of a (UNC) root
|
|
rootEnd = offset = j + 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else if (_util_ts_1.isWindowsDeviceRoot(code)) {
|
|
// Possible device root
|
|
if (path.charCodeAt(1) === _constants_ts_2.CHAR_COLON) {
|
|
rootEnd = offset = 2;
|
|
if (len > 2) {
|
|
if (_util_ts_1.isPathSeparator(path.charCodeAt(2))) {
|
|
rootEnd = offset = 3;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else if (_util_ts_1.isPathSeparator(code)) {
|
|
// `path` contains just a path separator, exit early to avoid
|
|
// unnecessary work
|
|
return path;
|
|
}
|
|
for (let i = len - 1; i >= offset; --i) {
|
|
if (_util_ts_1.isPathSeparator(path.charCodeAt(i))) {
|
|
if (!matchedSlash) {
|
|
end = i;
|
|
break;
|
|
}
|
|
} else {
|
|
// We saw the first non-path separator
|
|
matchedSlash = false;
|
|
}
|
|
}
|
|
if (end === -1) {
|
|
if (rootEnd === -1) {
|
|
return ".";
|
|
} else {
|
|
end = rootEnd;
|
|
}
|
|
}
|
|
return path.slice(0, end);
|
|
}
|
|
exports_8("dirname", dirname);
|
|
function basename(path, ext = "") {
|
|
if (ext !== undefined && typeof ext !== "string") {
|
|
throw new TypeError('"ext" argument must be a string');
|
|
}
|
|
_util_ts_1.assertPath(path);
|
|
let start = 0;
|
|
let end = -1;
|
|
let matchedSlash = true;
|
|
let i;
|
|
// Check for a drive letter prefix so as not to mistake the following
|
|
// path separator as an extra separator at the end of the path that can be
|
|
// disregarded
|
|
if (path.length >= 2) {
|
|
const drive = path.charCodeAt(0);
|
|
if (_util_ts_1.isWindowsDeviceRoot(drive)) {
|
|
if (path.charCodeAt(1) === _constants_ts_2.CHAR_COLON) {
|
|
start = 2;
|
|
}
|
|
}
|
|
}
|
|
if (ext !== undefined && ext.length > 0 && ext.length <= path.length) {
|
|
if (ext.length === path.length && ext === path) {
|
|
return "";
|
|
}
|
|
let extIdx = ext.length - 1;
|
|
let firstNonSlashEnd = -1;
|
|
for (i = path.length - 1; i >= start; --i) {
|
|
const code = path.charCodeAt(i);
|
|
if (_util_ts_1.isPathSeparator(code)) {
|
|
// If we reached a path separator that was not part of a set of path
|
|
// separators at the end of the string, stop now
|
|
if (!matchedSlash) {
|
|
start = i + 1;
|
|
break;
|
|
}
|
|
} else {
|
|
if (firstNonSlashEnd === -1) {
|
|
// We saw the first non-path separator, remember this index in case
|
|
// we need it if the extension ends up not matching
|
|
matchedSlash = false;
|
|
firstNonSlashEnd = i + 1;
|
|
}
|
|
if (extIdx >= 0) {
|
|
// Try to match the explicit extension
|
|
if (code === ext.charCodeAt(extIdx)) {
|
|
if (--extIdx === -1) {
|
|
// We matched the extension, so mark this as the end of our path
|
|
// component
|
|
end = i;
|
|
}
|
|
} else {
|
|
// Extension does not match, so our result is the entire path
|
|
// component
|
|
extIdx = -1;
|
|
end = firstNonSlashEnd;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (start === end) {
|
|
end = firstNonSlashEnd;
|
|
} else if (end === -1) {
|
|
end = path.length;
|
|
}
|
|
return path.slice(start, end);
|
|
} else {
|
|
for (i = path.length - 1; i >= start; --i) {
|
|
if (_util_ts_1.isPathSeparator(path.charCodeAt(i))) {
|
|
// If we reached a path separator that was not part of a set of path
|
|
// separators at the end of the string, stop now
|
|
if (!matchedSlash) {
|
|
start = i + 1;
|
|
break;
|
|
}
|
|
} else if (end === -1) {
|
|
// We saw the first non-path separator, mark this as the end of our
|
|
// path component
|
|
matchedSlash = false;
|
|
end = i + 1;
|
|
}
|
|
}
|
|
if (end === -1) {
|
|
return "";
|
|
}
|
|
return path.slice(start, end);
|
|
}
|
|
}
|
|
exports_8("basename", basename);
|
|
function extname(path) {
|
|
_util_ts_1.assertPath(path);
|
|
let start = 0;
|
|
let startDot = -1;
|
|
let startPart = 0;
|
|
let end = -1;
|
|
let matchedSlash = true;
|
|
// Track the state of characters (if any) we see before our first dot and
|
|
// after any path separator we find
|
|
let preDotState = 0;
|
|
// Check for a drive letter prefix so as not to mistake the following
|
|
// path separator as an extra separator at the end of the path that can be
|
|
// disregarded
|
|
if (
|
|
path.length >= 2 &&
|
|
path.charCodeAt(1) === _constants_ts_2.CHAR_COLON &&
|
|
_util_ts_1.isWindowsDeviceRoot(path.charCodeAt(0))
|
|
) {
|
|
start = startPart = 2;
|
|
}
|
|
for (let i = path.length - 1; i >= start; --i) {
|
|
const code = path.charCodeAt(i);
|
|
if (_util_ts_1.isPathSeparator(code)) {
|
|
// If we reached a path separator that was not part of a set of path
|
|
// separators at the end of the string, stop now
|
|
if (!matchedSlash) {
|
|
startPart = i + 1;
|
|
break;
|
|
}
|
|
continue;
|
|
}
|
|
if (end === -1) {
|
|
// We saw the first non-path separator, mark this as the end of our
|
|
// extension
|
|
matchedSlash = false;
|
|
end = i + 1;
|
|
}
|
|
if (code === _constants_ts_2.CHAR_DOT) {
|
|
// If this is our first dot, mark it as the start of our extension
|
|
if (startDot === -1) {
|
|
startDot = i;
|
|
} else if (preDotState !== 1) {
|
|
preDotState = 1;
|
|
}
|
|
} else if (startDot !== -1) {
|
|
// We saw a non-dot and non-path separator before our dot, so we should
|
|
// have a good chance at having a non-empty extension
|
|
preDotState = -1;
|
|
}
|
|
}
|
|
if (
|
|
startDot === -1 ||
|
|
end === -1 ||
|
|
// We saw a non-dot character immediately before the dot
|
|
preDotState === 0 ||
|
|
// The (right-most) trimmed path component is exactly '..'
|
|
(preDotState === 1 && startDot === end - 1 &&
|
|
startDot === startPart + 1)
|
|
) {
|
|
return "";
|
|
}
|
|
return path.slice(startDot, end);
|
|
}
|
|
exports_8("extname", extname);
|
|
function format(pathObject) {
|
|
/* eslint-disable max-len */
|
|
if (pathObject === null || typeof pathObject !== "object") {
|
|
throw new TypeError(
|
|
`The "pathObject" argument must be of type Object. Received type ${typeof pathObject}`,
|
|
);
|
|
}
|
|
return _util_ts_1._format("\\", pathObject);
|
|
}
|
|
exports_8("format", format);
|
|
function parse(path) {
|
|
_util_ts_1.assertPath(path);
|
|
const ret = { root: "", dir: "", base: "", ext: "", name: "" };
|
|
const len = path.length;
|
|
if (len === 0) {
|
|
return ret;
|
|
}
|
|
let rootEnd = 0;
|
|
let code = path.charCodeAt(0);
|
|
// Try to match a root
|
|
if (len > 1) {
|
|
if (_util_ts_1.isPathSeparator(code)) {
|
|
// Possible UNC root
|
|
rootEnd = 1;
|
|
if (_util_ts_1.isPathSeparator(path.charCodeAt(1))) {
|
|
// Matched double path separator at beginning
|
|
let j = 2;
|
|
let last = j;
|
|
// Match 1 or more non-path separators
|
|
for (; j < len; ++j) {
|
|
if (_util_ts_1.isPathSeparator(path.charCodeAt(j))) {
|
|
break;
|
|
}
|
|
}
|
|
if (j < len && j !== last) {
|
|
// Matched!
|
|
last = j;
|
|
// Match 1 or more path separators
|
|
for (; j < len; ++j) {
|
|
if (!_util_ts_1.isPathSeparator(path.charCodeAt(j))) {
|
|
break;
|
|
}
|
|
}
|
|
if (j < len && j !== last) {
|
|
// Matched!
|
|
last = j;
|
|
// Match 1 or more non-path separators
|
|
for (; j < len; ++j) {
|
|
if (_util_ts_1.isPathSeparator(path.charCodeAt(j))) {
|
|
break;
|
|
}
|
|
}
|
|
if (j === len) {
|
|
// We matched a UNC root only
|
|
rootEnd = j;
|
|
} else if (j !== last) {
|
|
// We matched a UNC root with leftovers
|
|
rootEnd = j + 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else if (_util_ts_1.isWindowsDeviceRoot(code)) {
|
|
// Possible device root
|
|
if (path.charCodeAt(1) === _constants_ts_2.CHAR_COLON) {
|
|
rootEnd = 2;
|
|
if (len > 2) {
|
|
if (_util_ts_1.isPathSeparator(path.charCodeAt(2))) {
|
|
if (len === 3) {
|
|
// `path` contains just a drive root, exit early to avoid
|
|
// unnecessary work
|
|
ret.root = ret.dir = path;
|
|
return ret;
|
|
}
|
|
rootEnd = 3;
|
|
}
|
|
} else {
|
|
// `path` contains just a drive root, exit early to avoid
|
|
// unnecessary work
|
|
ret.root = ret.dir = path;
|
|
return ret;
|
|
}
|
|
}
|
|
}
|
|
} else if (_util_ts_1.isPathSeparator(code)) {
|
|
// `path` contains just a path separator, exit early to avoid
|
|
// unnecessary work
|
|
ret.root = ret.dir = path;
|
|
return ret;
|
|
}
|
|
if (rootEnd > 0) {
|
|
ret.root = path.slice(0, rootEnd);
|
|
}
|
|
let startDot = -1;
|
|
let startPart = rootEnd;
|
|
let end = -1;
|
|
let matchedSlash = true;
|
|
let i = path.length - 1;
|
|
// Track the state of characters (if any) we see before our first dot and
|
|
// after any path separator we find
|
|
let preDotState = 0;
|
|
// Get non-dir info
|
|
for (; i >= rootEnd; --i) {
|
|
code = path.charCodeAt(i);
|
|
if (_util_ts_1.isPathSeparator(code)) {
|
|
// If we reached a path separator that was not part of a set of path
|
|
// separators at the end of the string, stop now
|
|
if (!matchedSlash) {
|
|
startPart = i + 1;
|
|
break;
|
|
}
|
|
continue;
|
|
}
|
|
if (end === -1) {
|
|
// We saw the first non-path separator, mark this as the end of our
|
|
// extension
|
|
matchedSlash = false;
|
|
end = i + 1;
|
|
}
|
|
if (code === _constants_ts_2.CHAR_DOT) {
|
|
// If this is our first dot, mark it as the start of our extension
|
|
if (startDot === -1) {
|
|
startDot = i;
|
|
} else if (preDotState !== 1) {
|
|
preDotState = 1;
|
|
}
|
|
} else if (startDot !== -1) {
|
|
// We saw a non-dot and non-path separator before our dot, so we should
|
|
// have a good chance at having a non-empty extension
|
|
preDotState = -1;
|
|
}
|
|
}
|
|
if (
|
|
startDot === -1 ||
|
|
end === -1 ||
|
|
// We saw a non-dot character immediately before the dot
|
|
preDotState === 0 ||
|
|
// The (right-most) trimmed path component is exactly '..'
|
|
(preDotState === 1 && startDot === end - 1 &&
|
|
startDot === startPart + 1)
|
|
) {
|
|
if (end !== -1) {
|
|
ret.base = ret.name = path.slice(startPart, end);
|
|
}
|
|
} else {
|
|
ret.name = path.slice(startPart, startDot);
|
|
ret.base = path.slice(startPart, end);
|
|
ret.ext = path.slice(startDot, end);
|
|
}
|
|
// If the directory is the root, use the entire root as the `dir` including
|
|
// the trailing slash if any (`C:\abc` -> `C:\`). Otherwise, strip out the
|
|
// trailing slash (`C:\abc\def` -> `C:\abc`).
|
|
if (startPart > 0 && startPart !== rootEnd) {
|
|
ret.dir = path.slice(0, startPart - 1);
|
|
} else {
|
|
ret.dir = ret.root;
|
|
}
|
|
return ret;
|
|
}
|
|
exports_8("parse", parse);
|
|
/** Converts a file URL to a path string.
|
|
*
|
|
* fromFileUrl("file:///C:/Users/foo"); // "C:\\Users\\foo"
|
|
* fromFileUrl("file:///home/foo"); // "\\home\\foo"
|
|
*
|
|
* Note that non-file URLs are treated as file URLs and irrelevant components
|
|
* are ignored.
|
|
*/
|
|
function fromFileUrl(url) {
|
|
return new URL(url).pathname
|
|
.replace(/^\/*([A-Za-z]:)(\/|$)/, "$1/")
|
|
.replace(/\//g, "\\");
|
|
}
|
|
exports_8("fromFileUrl", fromFileUrl);
|
|
return {
|
|
setters: [
|
|
function (_constants_ts_2_1) {
|
|
_constants_ts_2 = _constants_ts_2_1;
|
|
},
|
|
function (_util_ts_1_1) {
|
|
_util_ts_1 = _util_ts_1_1;
|
|
},
|
|
function (asserts_ts_1_1) {
|
|
asserts_ts_1 = asserts_ts_1_1;
|
|
},
|
|
],
|
|
execute: function () {
|
|
exports_8("sep", sep = "\\");
|
|
exports_8("delimiter", delimiter = ";");
|
|
},
|
|
};
|
|
},
|
|
);
|
|
// Copyright the Browserify authors. MIT License.
|
|
// Ported from https://github.com/browserify/path-browserify/
|
|
/** This module is browser compatible. */
|
|
System.register(
|
|
"https://deno.land/std@0.56.0/path/posix",
|
|
[
|
|
"https://deno.land/std@0.56.0/path/_constants",
|
|
"https://deno.land/std@0.56.0/path/_util",
|
|
],
|
|
function (exports_9, context_9) {
|
|
"use strict";
|
|
var _constants_ts_3, _util_ts_2, sep, delimiter;
|
|
var __moduleName = context_9 && context_9.id;
|
|
// path.resolve([from ...], to)
|
|
function resolve(...pathSegments) {
|
|
let resolvedPath = "";
|
|
let resolvedAbsolute = false;
|
|
for (let i = pathSegments.length - 1; i >= -1 && !resolvedAbsolute; i--) {
|
|
let path;
|
|
if (i >= 0) {
|
|
path = pathSegments[i];
|
|
} else {
|
|
if (globalThis.Deno == null) {
|
|
throw new TypeError("Resolved a relative path without a CWD.");
|
|
}
|
|
path = Deno.cwd();
|
|
}
|
|
_util_ts_2.assertPath(path);
|
|
// Skip empty entries
|
|
if (path.length === 0) {
|
|
continue;
|
|
}
|
|
resolvedPath = `${path}/${resolvedPath}`;
|
|
resolvedAbsolute =
|
|
path.charCodeAt(0) === _constants_ts_3.CHAR_FORWARD_SLASH;
|
|
}
|
|
// At this point the path should be resolved to a full absolute path, but
|
|
// handle relative paths to be safe (might happen when process.cwd() fails)
|
|
// Normalize the path
|
|
resolvedPath = _util_ts_2.normalizeString(
|
|
resolvedPath,
|
|
!resolvedAbsolute,
|
|
"/",
|
|
_util_ts_2.isPosixPathSeparator,
|
|
);
|
|
if (resolvedAbsolute) {
|
|
if (resolvedPath.length > 0) {
|
|
return `/${resolvedPath}`;
|
|
} else {
|
|
return "/";
|
|
}
|
|
} else if (resolvedPath.length > 0) {
|
|
return resolvedPath;
|
|
} else {
|
|
return ".";
|
|
}
|
|
}
|
|
exports_9("resolve", resolve);
|
|
function normalize(path) {
|
|
_util_ts_2.assertPath(path);
|
|
if (path.length === 0) {
|
|
return ".";
|
|
}
|
|
const isAbsolute =
|
|
path.charCodeAt(0) === _constants_ts_3.CHAR_FORWARD_SLASH;
|
|
const trailingSeparator =
|
|
path.charCodeAt(path.length - 1) === _constants_ts_3.CHAR_FORWARD_SLASH;
|
|
// Normalize the path
|
|
path = _util_ts_2.normalizeString(
|
|
path,
|
|
!isAbsolute,
|
|
"/",
|
|
_util_ts_2.isPosixPathSeparator,
|
|
);
|
|
if (path.length === 0 && !isAbsolute) {
|
|
path = ".";
|
|
}
|
|
if (path.length > 0 && trailingSeparator) {
|
|
path += "/";
|
|
}
|
|
if (isAbsolute) {
|
|
return `/${path}`;
|
|
}
|
|
return path;
|
|
}
|
|
exports_9("normalize", normalize);
|
|
function isAbsolute(path) {
|
|
_util_ts_2.assertPath(path);
|
|
return path.length > 0 &&
|
|
path.charCodeAt(0) === _constants_ts_3.CHAR_FORWARD_SLASH;
|
|
}
|
|
exports_9("isAbsolute", isAbsolute);
|
|
function join(...paths) {
|
|
if (paths.length === 0) {
|
|
return ".";
|
|
}
|
|
let joined;
|
|
for (let i = 0, len = paths.length; i < len; ++i) {
|
|
const path = paths[i];
|
|
_util_ts_2.assertPath(path);
|
|
if (path.length > 0) {
|
|
if (!joined) {
|
|
joined = path;
|
|
} else {
|
|
joined += `/${path}`;
|
|
}
|
|
}
|
|
}
|
|
if (!joined) {
|
|
return ".";
|
|
}
|
|
return normalize(joined);
|
|
}
|
|
exports_9("join", join);
|
|
function relative(from, to) {
|
|
_util_ts_2.assertPath(from);
|
|
_util_ts_2.assertPath(to);
|
|
if (from === to) {
|
|
return "";
|
|
}
|
|
from = resolve(from);
|
|
to = resolve(to);
|
|
if (from === to) {
|
|
return "";
|
|
}
|
|
// Trim any leading backslashes
|
|
let fromStart = 1;
|
|
const fromEnd = from.length;
|
|
for (; fromStart < fromEnd; ++fromStart) {
|
|
if (from.charCodeAt(fromStart) !== _constants_ts_3.CHAR_FORWARD_SLASH) {
|
|
break;
|
|
}
|
|
}
|
|
const fromLen = fromEnd - fromStart;
|
|
// Trim any leading backslashes
|
|
let toStart = 1;
|
|
const toEnd = to.length;
|
|
for (; toStart < toEnd; ++toStart) {
|
|
if (to.charCodeAt(toStart) !== _constants_ts_3.CHAR_FORWARD_SLASH) {
|
|
break;
|
|
}
|
|
}
|
|
const toLen = toEnd - toStart;
|
|
// Compare paths to find the longest common path from root
|
|
const length = fromLen < toLen ? fromLen : toLen;
|
|
let lastCommonSep = -1;
|
|
let i = 0;
|
|
for (; i <= length; ++i) {
|
|
if (i === length) {
|
|
if (toLen > length) {
|
|
if (
|
|
to.charCodeAt(toStart + i) === _constants_ts_3.CHAR_FORWARD_SLASH
|
|
) {
|
|
// We get here if `from` is the exact base path for `to`.
|
|
// For example: from='/foo/bar'; to='/foo/bar/baz'
|
|
return to.slice(toStart + i + 1);
|
|
} else if (i === 0) {
|
|
// We get here if `from` is the root
|
|
// For example: from='/'; to='/foo'
|
|
return to.slice(toStart + i);
|
|
}
|
|
} else if (fromLen > length) {
|
|
if (
|
|
from.charCodeAt(fromStart + i) ===
|
|
_constants_ts_3.CHAR_FORWARD_SLASH
|
|
) {
|
|
// We get here if `to` is the exact base path for `from`.
|
|
// For example: from='/foo/bar/baz'; to='/foo/bar'
|
|
lastCommonSep = i;
|
|
} else if (i === 0) {
|
|
// We get here if `to` is the root.
|
|
// For example: from='/foo'; to='/'
|
|
lastCommonSep = 0;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
const fromCode = from.charCodeAt(fromStart + i);
|
|
const toCode = to.charCodeAt(toStart + i);
|
|
if (fromCode !== toCode) {
|
|
break;
|
|
} else if (fromCode === _constants_ts_3.CHAR_FORWARD_SLASH) {
|
|
lastCommonSep = i;
|
|
}
|
|
}
|
|
let out = "";
|
|
// Generate the relative path based on the path difference between `to`
|
|
// and `from`
|
|
for (i = fromStart + lastCommonSep + 1; i <= fromEnd; ++i) {
|
|
if (
|
|
i === fromEnd ||
|
|
from.charCodeAt(i) === _constants_ts_3.CHAR_FORWARD_SLASH
|
|
) {
|
|
if (out.length === 0) {
|
|
out += "..";
|
|
} else {
|
|
out += "/..";
|
|
}
|
|
}
|
|
}
|
|
// Lastly, append the rest of the destination (`to`) path that comes after
|
|
// the common path parts
|
|
if (out.length > 0) {
|
|
return out + to.slice(toStart + lastCommonSep);
|
|
} else {
|
|
toStart += lastCommonSep;
|
|
if (to.charCodeAt(toStart) === _constants_ts_3.CHAR_FORWARD_SLASH) {
|
|
++toStart;
|
|
}
|
|
return to.slice(toStart);
|
|
}
|
|
}
|
|
exports_9("relative", relative);
|
|
function toNamespacedPath(path) {
|
|
// Non-op on posix systems
|
|
return path;
|
|
}
|
|
exports_9("toNamespacedPath", toNamespacedPath);
|
|
function dirname(path) {
|
|
_util_ts_2.assertPath(path);
|
|
if (path.length === 0) {
|
|
return ".";
|
|
}
|
|
const hasRoot = path.charCodeAt(0) === _constants_ts_3.CHAR_FORWARD_SLASH;
|
|
let end = -1;
|
|
let matchedSlash = true;
|
|
for (let i = path.length - 1; i >= 1; --i) {
|
|
if (path.charCodeAt(i) === _constants_ts_3.CHAR_FORWARD_SLASH) {
|
|
if (!matchedSlash) {
|
|
end = i;
|
|
break;
|
|
}
|
|
} else {
|
|
// We saw the first non-path separator
|
|
matchedSlash = false;
|
|
}
|
|
}
|
|
if (end === -1) {
|
|
return hasRoot ? "/" : ".";
|
|
}
|
|
if (hasRoot && end === 1) {
|
|
return "//";
|
|
}
|
|
return path.slice(0, end);
|
|
}
|
|
exports_9("dirname", dirname);
|
|
function basename(path, ext = "") {
|
|
if (ext !== undefined && typeof ext !== "string") {
|
|
throw new TypeError('"ext" argument must be a string');
|
|
}
|
|
_util_ts_2.assertPath(path);
|
|
let start = 0;
|
|
let end = -1;
|
|
let matchedSlash = true;
|
|
let i;
|
|
if (ext !== undefined && ext.length > 0 && ext.length <= path.length) {
|
|
if (ext.length === path.length && ext === path) {
|
|
return "";
|
|
}
|
|
let extIdx = ext.length - 1;
|
|
let firstNonSlashEnd = -1;
|
|
for (i = path.length - 1; i >= 0; --i) {
|
|
const code = path.charCodeAt(i);
|
|
if (code === _constants_ts_3.CHAR_FORWARD_SLASH) {
|
|
// If we reached a path separator that was not part of a set of path
|
|
// separators at the end of the string, stop now
|
|
if (!matchedSlash) {
|
|
start = i + 1;
|
|
break;
|
|
}
|
|
} else {
|
|
if (firstNonSlashEnd === -1) {
|
|
// We saw the first non-path separator, remember this index in case
|
|
// we need it if the extension ends up not matching
|
|
matchedSlash = false;
|
|
firstNonSlashEnd = i + 1;
|
|
}
|
|
if (extIdx >= 0) {
|
|
// Try to match the explicit extension
|
|
if (code === ext.charCodeAt(extIdx)) {
|
|
if (--extIdx === -1) {
|
|
// We matched the extension, so mark this as the end of our path
|
|
// component
|
|
end = i;
|
|
}
|
|
} else {
|
|
// Extension does not match, so our result is the entire path
|
|
// component
|
|
extIdx = -1;
|
|
end = firstNonSlashEnd;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (start === end) {
|
|
end = firstNonSlashEnd;
|
|
} else if (end === -1) {
|
|
end = path.length;
|
|
}
|
|
return path.slice(start, end);
|
|
} else {
|
|
for (i = path.length - 1; i >= 0; --i) {
|
|
if (path.charCodeAt(i) === _constants_ts_3.CHAR_FORWARD_SLASH) {
|
|
// If we reached a path separator that was not part of a set of path
|
|
// separators at the end of the string, stop now
|
|
if (!matchedSlash) {
|
|
start = i + 1;
|
|
break;
|
|
}
|
|
} else if (end === -1) {
|
|
// We saw the first non-path separator, mark this as the end of our
|
|
// path component
|
|
matchedSlash = false;
|
|
end = i + 1;
|
|
}
|
|
}
|
|
if (end === -1) {
|
|
return "";
|
|
}
|
|
return path.slice(start, end);
|
|
}
|
|
}
|
|
exports_9("basename", basename);
|
|
function extname(path) {
|
|
_util_ts_2.assertPath(path);
|
|
let startDot = -1;
|
|
let startPart = 0;
|
|
let end = -1;
|
|
let matchedSlash = true;
|
|
// Track the state of characters (if any) we see before our first dot and
|
|
// after any path separator we find
|
|
let preDotState = 0;
|
|
for (let i = path.length - 1; i >= 0; --i) {
|
|
const code = path.charCodeAt(i);
|
|
if (code === _constants_ts_3.CHAR_FORWARD_SLASH) {
|
|
// If we reached a path separator that was not part of a set of path
|
|
// separators at the end of the string, stop now
|
|
if (!matchedSlash) {
|
|
startPart = i + 1;
|
|
break;
|
|
}
|
|
continue;
|
|
}
|
|
if (end === -1) {
|
|
// We saw the first non-path separator, mark this as the end of our
|
|
// extension
|
|
matchedSlash = false;
|
|
end = i + 1;
|
|
}
|
|
if (code === _constants_ts_3.CHAR_DOT) {
|
|
// If this is our first dot, mark it as the start of our extension
|
|
if (startDot === -1) {
|
|
startDot = i;
|
|
} else if (preDotState !== 1) {
|
|
preDotState = 1;
|
|
}
|
|
} else if (startDot !== -1) {
|
|
// We saw a non-dot and non-path separator before our dot, so we should
|
|
// have a good chance at having a non-empty extension
|
|
preDotState = -1;
|
|
}
|
|
}
|
|
if (
|
|
startDot === -1 ||
|
|
end === -1 ||
|
|
// We saw a non-dot character immediately before the dot
|
|
preDotState === 0 ||
|
|
// The (right-most) trimmed path component is exactly '..'
|
|
(preDotState === 1 && startDot === end - 1 &&
|
|
startDot === startPart + 1)
|
|
) {
|
|
return "";
|
|
}
|
|
return path.slice(startDot, end);
|
|
}
|
|
exports_9("extname", extname);
|
|
function format(pathObject) {
|
|
/* eslint-disable max-len */
|
|
if (pathObject === null || typeof pathObject !== "object") {
|
|
throw new TypeError(
|
|
`The "pathObject" argument must be of type Object. Received type ${typeof pathObject}`,
|
|
);
|
|
}
|
|
return _util_ts_2._format("/", pathObject);
|
|
}
|
|
exports_9("format", format);
|
|
function parse(path) {
|
|
_util_ts_2.assertPath(path);
|
|
const ret = { root: "", dir: "", base: "", ext: "", name: "" };
|
|
if (path.length === 0) {
|
|
return ret;
|
|
}
|
|
const isAbsolute =
|
|
path.charCodeAt(0) === _constants_ts_3.CHAR_FORWARD_SLASH;
|
|
let start;
|
|
if (isAbsolute) {
|
|
ret.root = "/";
|
|
start = 1;
|
|
} else {
|
|
start = 0;
|
|
}
|
|
let startDot = -1;
|
|
let startPart = 0;
|
|
let end = -1;
|
|
let matchedSlash = true;
|
|
let i = path.length - 1;
|
|
// Track the state of characters (if any) we see before our first dot and
|
|
// after any path separator we find
|
|
let preDotState = 0;
|
|
// Get non-dir info
|
|
for (; i >= start; --i) {
|
|
const code = path.charCodeAt(i);
|
|
if (code === _constants_ts_3.CHAR_FORWARD_SLASH) {
|
|
// If we reached a path separator that was not part of a set of path
|
|
// separators at the end of the string, stop now
|
|
if (!matchedSlash) {
|
|
startPart = i + 1;
|
|
break;
|
|
}
|
|
continue;
|
|
}
|
|
if (end === -1) {
|
|
// We saw the first non-path separator, mark this as the end of our
|
|
// extension
|
|
matchedSlash = false;
|
|
end = i + 1;
|
|
}
|
|
if (code === _constants_ts_3.CHAR_DOT) {
|
|
// If this is our first dot, mark it as the start of our extension
|
|
if (startDot === -1) {
|
|
startDot = i;
|
|
} else if (preDotState !== 1) {
|
|
preDotState = 1;
|
|
}
|
|
} else if (startDot !== -1) {
|
|
// We saw a non-dot and non-path separator before our dot, so we should
|
|
// have a good chance at having a non-empty extension
|
|
preDotState = -1;
|
|
}
|
|
}
|
|
if (
|
|
startDot === -1 ||
|
|
end === -1 ||
|
|
// We saw a non-dot character immediately before the dot
|
|
preDotState === 0 ||
|
|
// The (right-most) trimmed path component is exactly '..'
|
|
(preDotState === 1 && startDot === end - 1 &&
|
|
startDot === startPart + 1)
|
|
) {
|
|
if (end !== -1) {
|
|
if (startPart === 0 && isAbsolute) {
|
|
ret.base = ret.name = path.slice(1, end);
|
|
} else {
|
|
ret.base = ret.name = path.slice(startPart, end);
|
|
}
|
|
}
|
|
} else {
|
|
if (startPart === 0 && isAbsolute) {
|
|
ret.name = path.slice(1, startDot);
|
|
ret.base = path.slice(1, end);
|
|
} else {
|
|
ret.name = path.slice(startPart, startDot);
|
|
ret.base = path.slice(startPart, end);
|
|
}
|
|
ret.ext = path.slice(startDot, end);
|
|
}
|
|
if (startPart > 0) {
|
|
ret.dir = path.slice(0, startPart - 1);
|
|
} else if (isAbsolute) {
|
|
ret.dir = "/";
|
|
}
|
|
return ret;
|
|
}
|
|
exports_9("parse", parse);
|
|
/** Converts a file URL to a path string.
|
|
*
|
|
* fromFileUrl("file:///home/foo"); // "/home/foo"
|
|
*
|
|
* Note that non-file URLs are treated as file URLs and irrelevant components
|
|
* are ignored.
|
|
*/
|
|
function fromFileUrl(url) {
|
|
return new URL(url).pathname;
|
|
}
|
|
exports_9("fromFileUrl", fromFileUrl);
|
|
return {
|
|
setters: [
|
|
function (_constants_ts_3_1) {
|
|
_constants_ts_3 = _constants_ts_3_1;
|
|
},
|
|
function (_util_ts_2_1) {
|
|
_util_ts_2 = _util_ts_2_1;
|
|
},
|
|
],
|
|
execute: function () {
|
|
exports_9("sep", sep = "/");
|
|
exports_9("delimiter", delimiter = ":");
|
|
},
|
|
};
|
|
},
|
|
);
|
|
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
|
/** This module is browser compatible. */
|
|
System.register(
|
|
"https://deno.land/std@0.56.0/path/separator",
|
|
["https://deno.land/std@0.56.0/path/_constants"],
|
|
function (exports_10, context_10) {
|
|
"use strict";
|
|
var _constants_ts_4, SEP, SEP_PATTERN;
|
|
var __moduleName = context_10 && context_10.id;
|
|
return {
|
|
setters: [
|
|
function (_constants_ts_4_1) {
|
|
_constants_ts_4 = _constants_ts_4_1;
|
|
},
|
|
],
|
|
execute: function () {
|
|
exports_10("SEP", SEP = _constants_ts_4.isWindows ? "\\" : "/");
|
|
exports_10(
|
|
"SEP_PATTERN",
|
|
SEP_PATTERN = _constants_ts_4.isWindows ? /[\\/]+/ : /\/+/,
|
|
);
|
|
},
|
|
};
|
|
},
|
|
);
|
|
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
|
/** This module is browser compatible. */
|
|
System.register(
|
|
"https://deno.land/std@0.56.0/path/common",
|
|
["https://deno.land/std@0.56.0/path/separator"],
|
|
function (exports_11, context_11) {
|
|
"use strict";
|
|
var separator_ts_1;
|
|
var __moduleName = context_11 && context_11.id;
|
|
/** 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/"
|
|
*
|
|
*/
|
|
function common(paths, sep = separator_ts_1.SEP) {
|
|
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}`;
|
|
}
|
|
exports_11("common", common);
|
|
return {
|
|
setters: [
|
|
function (separator_ts_1_1) {
|
|
separator_ts_1 = separator_ts_1_1;
|
|
},
|
|
],
|
|
execute: function () {
|
|
},
|
|
};
|
|
},
|
|
);
|
|
// This file is ported from globrex@0.1.2
|
|
// MIT License
|
|
// Copyright (c) 2018 Terkel Gjervig Nielsen
|
|
/** This module is browser compatible. */
|
|
System.register(
|
|
"https://deno.land/std@0.56.0/path/_globrex",
|
|
["https://deno.land/std@0.56.0/path/_constants"],
|
|
function (exports_12, context_12) {
|
|
"use strict";
|
|
var _constants_ts_5,
|
|
SEP,
|
|
SEP_ESC,
|
|
SEP_RAW,
|
|
GLOBSTAR,
|
|
WILDCARD,
|
|
GLOBSTAR_SEGMENT,
|
|
WILDCARD_SEGMENT;
|
|
var __moduleName = context_12 && context_12.id;
|
|
/**
|
|
* Convert any glob pattern to a JavaScript Regexp object
|
|
* @param glob Glob pattern to convert
|
|
* @param opts Configuration object
|
|
* @returns Converted object with string, segments and RegExp object
|
|
*/
|
|
function globrex(
|
|
glob,
|
|
{
|
|
extended = false,
|
|
globstar = false,
|
|
strict = false,
|
|
filepath = false,
|
|
flags = "",
|
|
} = {},
|
|
) {
|
|
const sepPattern = new RegExp(`^${SEP}${strict ? "" : "+"}$`);
|
|
let regex = "";
|
|
let segment = "";
|
|
let pathRegexStr = "";
|
|
const pathSegments = [];
|
|
// If we are doing extended matching, this boolean is true when we are inside
|
|
// a group (eg {*.html,*.js}), and false otherwise.
|
|
let inGroup = false;
|
|
let inRange = false;
|
|
// extglob stack. Keep track of scope
|
|
const ext = [];
|
|
// Helper function to build string and segments
|
|
function add(str, options = { split: false, last: false, only: "" }) {
|
|
const { split, last, only } = options;
|
|
if (only !== "path") {
|
|
regex += str;
|
|
}
|
|
if (filepath && only !== "regex") {
|
|
pathRegexStr += str.match(sepPattern) ? SEP : str;
|
|
if (split) {
|
|
if (last) {
|
|
segment += str;
|
|
}
|
|
if (segment !== "") {
|
|
// change it 'includes'
|
|
if (!flags.includes("g")) {
|
|
segment = `^${segment}$`;
|
|
}
|
|
pathSegments.push(new RegExp(segment, flags));
|
|
}
|
|
segment = "";
|
|
} else {
|
|
segment += str;
|
|
}
|
|
}
|
|
}
|
|
let c, n;
|
|
for (let i = 0; i < glob.length; i++) {
|
|
c = glob[i];
|
|
n = glob[i + 1];
|
|
if (["\\", "$", "^", ".", "="].includes(c)) {
|
|
add(`\\${c}`);
|
|
continue;
|
|
}
|
|
if (c.match(sepPattern)) {
|
|
add(SEP, { split: true });
|
|
if (n != null && n.match(sepPattern) && !strict) {
|
|
regex += "?";
|
|
}
|
|
continue;
|
|
}
|
|
if (c === "(") {
|
|
if (ext.length) {
|
|
add(`${c}?:`);
|
|
continue;
|
|
}
|
|
add(`\\${c}`);
|
|
continue;
|
|
}
|
|
if (c === ")") {
|
|
if (ext.length) {
|
|
add(c);
|
|
const type = ext.pop();
|
|
if (type === "@") {
|
|
add("{1}");
|
|
} else if (type === "!") {
|
|
add(WILDCARD);
|
|
} else {
|
|
add(type);
|
|
}
|
|
continue;
|
|
}
|
|
add(`\\${c}`);
|
|
continue;
|
|
}
|
|
if (c === "|") {
|
|
if (ext.length) {
|
|
add(c);
|
|
continue;
|
|
}
|
|
add(`\\${c}`);
|
|
continue;
|
|
}
|
|
if (c === "+") {
|
|
if (n === "(" && extended) {
|
|
ext.push(c);
|
|
continue;
|
|
}
|
|
add(`\\${c}`);
|
|
continue;
|
|
}
|
|
if (c === "@" && extended) {
|
|
if (n === "(") {
|
|
ext.push(c);
|
|
continue;
|
|
}
|
|
}
|
|
if (c === "!") {
|
|
if (extended) {
|
|
if (inRange) {
|
|
add("^");
|
|
continue;
|
|
}
|
|
if (n === "(") {
|
|
ext.push(c);
|
|
add("(?!");
|
|
i++;
|
|
continue;
|
|
}
|
|
add(`\\${c}`);
|
|
continue;
|
|
}
|
|
add(`\\${c}`);
|
|
continue;
|
|
}
|
|
if (c === "?") {
|
|
if (extended) {
|
|
if (n === "(") {
|
|
ext.push(c);
|
|
} else {
|
|
add(".");
|
|
}
|
|
continue;
|
|
}
|
|
add(`\\${c}`);
|
|
continue;
|
|
}
|
|
if (c === "[") {
|
|
if (inRange && n === ":") {
|
|
i++; // skip [
|
|
let value = "";
|
|
while (glob[++i] !== ":") {
|
|
value += glob[i];
|
|
}
|
|
if (value === "alnum") {
|
|
add("(?:\\w|\\d)");
|
|
} else if (value === "space") {
|
|
add("\\s");
|
|
} else if (value === "digit") {
|
|
add("\\d");
|
|
}
|
|
i++; // skip last ]
|
|
continue;
|
|
}
|
|
if (extended) {
|
|
inRange = true;
|
|
add(c);
|
|
continue;
|
|
}
|
|
add(`\\${c}`);
|
|
continue;
|
|
}
|
|
if (c === "]") {
|
|
if (extended) {
|
|
inRange = false;
|
|
add(c);
|
|
continue;
|
|
}
|
|
add(`\\${c}`);
|
|
continue;
|
|
}
|
|
if (c === "{") {
|
|
if (extended) {
|
|
inGroup = true;
|
|
add("(?:");
|
|
continue;
|
|
}
|
|
add(`\\${c}`);
|
|
continue;
|
|
}
|
|
if (c === "}") {
|
|
if (extended) {
|
|
inGroup = false;
|
|
add(")");
|
|
continue;
|
|
}
|
|
add(`\\${c}`);
|
|
continue;
|
|
}
|
|
if (c === ",") {
|
|
if (inGroup) {
|
|
add("|");
|
|
continue;
|
|
}
|
|
add(`\\${c}`);
|
|
continue;
|
|
}
|
|
if (c === "*") {
|
|
if (n === "(" && extended) {
|
|
ext.push(c);
|
|
continue;
|
|
}
|
|
// Move over all consecutive "*"'s.
|
|
// Also store the previous and next characters
|
|
const prevChar = glob[i - 1];
|
|
let starCount = 1;
|
|
while (glob[i + 1] === "*") {
|
|
starCount++;
|
|
i++;
|
|
}
|
|
const nextChar = glob[i + 1];
|
|
if (!globstar) {
|
|
// globstar is disabled, so treat any number of "*" as one
|
|
add(".*");
|
|
} else {
|
|
// globstar is enabled, so determine if this is a globstar segment
|
|
const isGlobstar = starCount > 1 && // multiple "*"'s
|
|
// from the start of the segment
|
|
[SEP_RAW, "/", undefined].includes(prevChar) &&
|
|
// to the end of the segment
|
|
[SEP_RAW, "/", undefined].includes(nextChar);
|
|
if (isGlobstar) {
|
|
// it's a globstar, so match zero or more path segments
|
|
add(GLOBSTAR, { only: "regex" });
|
|
add(GLOBSTAR_SEGMENT, { only: "path", last: true, split: true });
|
|
i++; // move over the "/"
|
|
} else {
|
|
// it's not a globstar, so only match one path segment
|
|
add(WILDCARD, { only: "regex" });
|
|
add(WILDCARD_SEGMENT, { only: "path" });
|
|
}
|
|
}
|
|
continue;
|
|
}
|
|
add(c);
|
|
}
|
|
// When regexp 'g' flag is specified don't
|
|
// constrain the regular expression with ^ & $
|
|
if (!flags.includes("g")) {
|
|
regex = `^${regex}$`;
|
|
segment = `^${segment}$`;
|
|
if (filepath) {
|
|
pathRegexStr = `^${pathRegexStr}$`;
|
|
}
|
|
}
|
|
const result = { regex: new RegExp(regex, flags) };
|
|
// Push the last segment
|
|
if (filepath) {
|
|
pathSegments.push(new RegExp(segment, flags));
|
|
result.path = {
|
|
regex: new RegExp(pathRegexStr, flags),
|
|
segments: pathSegments,
|
|
globstar: new RegExp(
|
|
!flags.includes("g") ? `^${GLOBSTAR_SEGMENT}$` : GLOBSTAR_SEGMENT,
|
|
flags,
|
|
),
|
|
};
|
|
}
|
|
return result;
|
|
}
|
|
exports_12("globrex", globrex);
|
|
return {
|
|
setters: [
|
|
function (_constants_ts_5_1) {
|
|
_constants_ts_5 = _constants_ts_5_1;
|
|
},
|
|
],
|
|
execute: function () {
|
|
SEP = _constants_ts_5.isWindows ? `(?:\\\\|\\/)` : `\\/`;
|
|
SEP_ESC = _constants_ts_5.isWindows ? `\\\\` : `/`;
|
|
SEP_RAW = _constants_ts_5.isWindows ? `\\` : `/`;
|
|
GLOBSTAR = `(?:(?:[^${SEP_ESC}/]*(?:${SEP_ESC}|\/|$))*)`;
|
|
WILDCARD = `(?:[^${SEP_ESC}/]*)`;
|
|
GLOBSTAR_SEGMENT = `((?:[^${SEP_ESC}/]*(?:${SEP_ESC}|\/|$))*)`;
|
|
WILDCARD_SEGMENT = `(?:[^${SEP_ESC}/]*)`;
|
|
},
|
|
};
|
|
},
|
|
);
|
|
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
|
/** This module is browser compatible. */
|
|
System.register(
|
|
"https://deno.land/std@0.56.0/path/glob",
|
|
[
|
|
"https://deno.land/std@0.56.0/path/separator",
|
|
"https://deno.land/std@0.56.0/path/_globrex",
|
|
"https://deno.land/std@0.56.0/path/mod",
|
|
"https://deno.land/std@0.56.0/testing/asserts",
|
|
],
|
|
function (exports_13, context_13) {
|
|
"use strict";
|
|
var separator_ts_2, _globrex_ts_1, mod_ts_1, asserts_ts_2;
|
|
var __moduleName = context_13 && context_13.id;
|
|
/**
|
|
* Generate a regex based on glob pattern and options
|
|
* This was meant to be using the the `fs.walk` function
|
|
* but can be used anywhere else.
|
|
* Examples:
|
|
*
|
|
* Looking for all the `ts` files:
|
|
* walkSync(".", {
|
|
* match: [globToRegExp("*.ts")]
|
|
* })
|
|
*
|
|
* Looking for all the `.json` files in any subfolder:
|
|
* walkSync(".", {
|
|
* match: [globToRegExp(join("a", "**", "*.json"),{
|
|
* flags: "g",
|
|
* extended: true,
|
|
* globstar: true
|
|
* })]
|
|
* })
|
|
*
|
|
* @param glob - Glob pattern to be used
|
|
* @param options - Specific options for the glob pattern
|
|
* @returns A RegExp for the glob pattern
|
|
*/
|
|
function globToRegExp(glob, { extended = false, globstar = true } = {}) {
|
|
const result = _globrex_ts_1.globrex(glob, {
|
|
extended,
|
|
globstar,
|
|
strict: false,
|
|
filepath: true,
|
|
});
|
|
asserts_ts_2.assert(result.path != null);
|
|
return result.path.regex;
|
|
}
|
|
exports_13("globToRegExp", globToRegExp);
|
|
/** Test whether the given string is a glob */
|
|
function isGlob(str) {
|
|
const chars = { "{": "}", "(": ")", "[": "]" };
|
|
/* eslint-disable-next-line max-len */
|
|
const regex =
|
|
/\\(.)|(^!|\*|[\].+)]\?|\[[^\\\]]+\]|\{[^\\}]+\}|\(\?[:!=][^\\)]+\)|\([^|]+\|[^\\)]+\))/;
|
|
if (str === "") {
|
|
return false;
|
|
}
|
|
let match;
|
|
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;
|
|
}
|
|
exports_13("isGlob", isGlob);
|
|
/** Like normalize(), but doesn't collapse "**\/.." when `globstar` is true. */
|
|
function normalizeGlob(glob, { globstar = false } = {}) {
|
|
if (!!glob.match(/\0/g)) {
|
|
throw new Error(`Glob contains invalid characters: "${glob}"`);
|
|
}
|
|
if (!globstar) {
|
|
return mod_ts_1.normalize(glob);
|
|
}
|
|
const s = separator_ts_2.SEP_PATTERN.source;
|
|
const badParentPattern = new RegExp(
|
|
`(?<=(${s}|^)\\*\\*${s})\\.\\.(?=${s}|$)`,
|
|
"g",
|
|
);
|
|
return mod_ts_1.normalize(glob.replace(badParentPattern, "\0")).replace(
|
|
/\0/g,
|
|
"..",
|
|
);
|
|
}
|
|
exports_13("normalizeGlob", normalizeGlob);
|
|
/** Like join(), but doesn't collapse "**\/.." when `globstar` is true. */
|
|
function joinGlobs(globs, { extended = false, globstar = false } = {}) {
|
|
if (!globstar || globs.length == 0) {
|
|
return mod_ts_1.join(...globs);
|
|
}
|
|
if (globs.length === 0) {
|
|
return ".";
|
|
}
|
|
let joined;
|
|
for (const glob of globs) {
|
|
const path = glob;
|
|
if (path.length > 0) {
|
|
if (!joined) {
|
|
joined = path;
|
|
} else {
|
|
joined += `${separator_ts_2.SEP}${path}`;
|
|
}
|
|
}
|
|
}
|
|
if (!joined) {
|
|
return ".";
|
|
}
|
|
return normalizeGlob(joined, { extended, globstar });
|
|
}
|
|
exports_13("joinGlobs", joinGlobs);
|
|
return {
|
|
setters: [
|
|
function (separator_ts_2_1) {
|
|
separator_ts_2 = separator_ts_2_1;
|
|
},
|
|
function (_globrex_ts_1_1) {
|
|
_globrex_ts_1 = _globrex_ts_1_1;
|
|
},
|
|
function (mod_ts_1_1) {
|
|
mod_ts_1 = mod_ts_1_1;
|
|
},
|
|
function (asserts_ts_2_1) {
|
|
asserts_ts_2 = asserts_ts_2_1;
|
|
},
|
|
],
|
|
execute: function () {
|
|
},
|
|
};
|
|
},
|
|
);
|
|
// Copyright the Browserify authors. MIT License.
|
|
// Ported mostly from https://github.com/browserify/path-browserify/
|
|
/** This module is browser compatible. */
|
|
System.register(
|
|
"https://deno.land/std@0.56.0/path/mod",
|
|
[
|
|
"https://deno.land/std@0.56.0/path/_constants",
|
|
"https://deno.land/std@0.56.0/path/win32",
|
|
"https://deno.land/std@0.56.0/path/posix",
|
|
"https://deno.land/std@0.56.0/path/common",
|
|
"https://deno.land/std@0.56.0/path/separator",
|
|
"https://deno.land/std@0.56.0/path/_interface",
|
|
"https://deno.land/std@0.56.0/path/glob",
|
|
],
|
|
function (exports_14, context_14) {
|
|
"use strict";
|
|
var _constants_ts_6,
|
|
_win32,
|
|
_posix,
|
|
path,
|
|
win32,
|
|
posix,
|
|
basename,
|
|
delimiter,
|
|
dirname,
|
|
extname,
|
|
format,
|
|
fromFileUrl,
|
|
isAbsolute,
|
|
join,
|
|
normalize,
|
|
parse,
|
|
relative,
|
|
resolve,
|
|
sep,
|
|
toNamespacedPath;
|
|
var __moduleName = context_14 && context_14.id;
|
|
var exportedNames_1 = {
|
|
"win32": true,
|
|
"posix": true,
|
|
"basename": true,
|
|
"delimiter": true,
|
|
"dirname": true,
|
|
"extname": true,
|
|
"format": true,
|
|
"fromFileUrl": true,
|
|
"isAbsolute": true,
|
|
"join": true,
|
|
"normalize": true,
|
|
"parse": true,
|
|
"relative": true,
|
|
"resolve": true,
|
|
"sep": true,
|
|
"toNamespacedPath": true,
|
|
"SEP": true,
|
|
"SEP_PATTERN": true,
|
|
};
|
|
function exportStar_1(m) {
|
|
var exports = {};
|
|
for (var n in m) {
|
|
if (n !== "default" && !exportedNames_1.hasOwnProperty(n)) {
|
|
exports[n] = m[n];
|
|
}
|
|
}
|
|
exports_14(exports);
|
|
}
|
|
return {
|
|
setters: [
|
|
function (_constants_ts_6_1) {
|
|
_constants_ts_6 = _constants_ts_6_1;
|
|
},
|
|
function (_win32_1) {
|
|
_win32 = _win32_1;
|
|
},
|
|
function (_posix_1) {
|
|
_posix = _posix_1;
|
|
},
|
|
function (common_ts_1_1) {
|
|
exportStar_1(common_ts_1_1);
|
|
},
|
|
function (separator_ts_3_1) {
|
|
exports_14({
|
|
"SEP": separator_ts_3_1["SEP"],
|
|
"SEP_PATTERN": separator_ts_3_1["SEP_PATTERN"],
|
|
});
|
|
},
|
|
function (_interface_ts_1_1) {
|
|
exportStar_1(_interface_ts_1_1);
|
|
},
|
|
function (glob_ts_1_1) {
|
|
exportStar_1(glob_ts_1_1);
|
|
},
|
|
],
|
|
execute: function () {
|
|
path = _constants_ts_6.isWindows ? _win32 : _posix;
|
|
exports_14("win32", win32 = _win32);
|
|
exports_14("posix", posix = _posix);
|
|
exports_14("basename", basename = path.basename),
|
|
exports_14("delimiter", delimiter = path.delimiter),
|
|
exports_14("dirname", dirname = path.dirname),
|
|
exports_14("extname", extname = path.extname),
|
|
exports_14("format", format = path.format),
|
|
exports_14("fromFileUrl", fromFileUrl = path.fromFileUrl),
|
|
exports_14("isAbsolute", isAbsolute = path.isAbsolute),
|
|
exports_14("join", join = path.join),
|
|
exports_14("normalize", normalize = path.normalize),
|
|
exports_14("parse", parse = path.parse),
|
|
exports_14("relative", relative = path.relative),
|
|
exports_14("resolve", resolve = path.resolve),
|
|
exports_14("sep", sep = path.sep),
|
|
exports_14(
|
|
"toNamespacedPath",
|
|
toNamespacedPath = path.toNamespacedPath,
|
|
);
|
|
},
|
|
};
|
|
},
|
|
);
|
|
System.register(
|
|
"https://deno.land/std@0.56.0/io/util",
|
|
[
|
|
"https://deno.land/std@0.56.0/path/mod",
|
|
"https://deno.land/std@0.56.0/encoding/utf8",
|
|
],
|
|
function (exports_15, context_15) {
|
|
"use strict";
|
|
var Buffer, mkdir, open, path, utf8_ts_1;
|
|
var __moduleName = context_15 && context_15.id;
|
|
/**
|
|
* Copy bytes from one Uint8Array to another. Bytes from `src` which don't fit
|
|
* into `dst` will not be copied.
|
|
*
|
|
* @param src Source byte array
|
|
* @param dst Destination byte array
|
|
* @param off Offset into `dst` at which to begin writing values from `src`.
|
|
* @return number of bytes copied
|
|
*/
|
|
function copyBytes(src, dst, off = 0) {
|
|
off = Math.max(0, Math.min(off, dst.byteLength));
|
|
const dstBytesAvailable = dst.byteLength - off;
|
|
if (src.byteLength > dstBytesAvailable) {
|
|
src = src.subarray(0, dstBytesAvailable);
|
|
}
|
|
dst.set(src, off);
|
|
return src.byteLength;
|
|
}
|
|
exports_15("copyBytes", copyBytes);
|
|
function charCode(s) {
|
|
return s.charCodeAt(0);
|
|
}
|
|
exports_15("charCode", charCode);
|
|
function stringsReader(s) {
|
|
return new Buffer(utf8_ts_1.encode(s).buffer);
|
|
}
|
|
exports_15("stringsReader", stringsReader);
|
|
/** Create or open a temporal file at specified directory with prefix and
|
|
* postfix
|
|
* */
|
|
async function tempFile(dir, opts = { prefix: "", postfix: "" }) {
|
|
const r = Math.floor(Math.random() * 1000000);
|
|
const filepath = path.resolve(
|
|
`${dir}/${opts.prefix || ""}${r}${opts.postfix || ""}`,
|
|
);
|
|
await mkdir(path.dirname(filepath), { recursive: true });
|
|
const file = await open(filepath, {
|
|
create: true,
|
|
read: true,
|
|
write: true,
|
|
append: true,
|
|
});
|
|
return { file, filepath };
|
|
}
|
|
exports_15("tempFile", tempFile);
|
|
return {
|
|
setters: [
|
|
function (path_1) {
|
|
path = path_1;
|
|
},
|
|
function (utf8_ts_1_1) {
|
|
utf8_ts_1 = utf8_ts_1_1;
|
|
},
|
|
],
|
|
execute: function () {
|
|
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
|
Buffer = Deno.Buffer, mkdir = Deno.mkdir, open = Deno.open;
|
|
},
|
|
};
|
|
},
|
|
);
|
|
// 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.
|
|
System.register(
|
|
"https://deno.land/std@0.56.0/io/bufio",
|
|
[
|
|
"https://deno.land/std@0.56.0/io/util",
|
|
"https://deno.land/std@0.56.0/testing/asserts",
|
|
],
|
|
function (exports_16, context_16) {
|
|
"use strict";
|
|
var util_ts_1,
|
|
asserts_ts_3,
|
|
DEFAULT_BUF_SIZE,
|
|
MIN_BUF_SIZE,
|
|
MAX_CONSECUTIVE_EMPTY_READS,
|
|
CR,
|
|
LF,
|
|
BufferFullError,
|
|
PartialReadError,
|
|
BufReader,
|
|
AbstractBufBase,
|
|
BufWriter,
|
|
BufWriterSync;
|
|
var __moduleName = context_16 && context_16.id;
|
|
/** Generate longest proper prefix which is also suffix array. */
|
|
function createLPS(pat) {
|
|
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. */
|
|
async function* readDelim(reader, delim) {
|
|
// 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 < 0) {
|
|
// Discard all remaining and silently fail.
|
|
return;
|
|
}
|
|
const sliceRead = inspectArr.subarray(0, result);
|
|
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);
|
|
}
|
|
}
|
|
exports_16("readDelim", readDelim);
|
|
/** Read delimited strings from a Reader. */
|
|
async function* readStringDelim(reader, delim) {
|
|
const encoder = new TextEncoder();
|
|
const decoder = new TextDecoder();
|
|
for await (const chunk of readDelim(reader, encoder.encode(delim))) {
|
|
yield decoder.decode(chunk);
|
|
}
|
|
}
|
|
exports_16("readStringDelim", readStringDelim);
|
|
/** Read strings line-by-line from a Reader. */
|
|
// eslint-disable-next-line require-await
|
|
async function* readLines(reader) {
|
|
yield* readStringDelim(reader, "\n");
|
|
}
|
|
exports_16("readLines", readLines);
|
|
return {
|
|
setters: [
|
|
function (util_ts_1_1) {
|
|
util_ts_1 = util_ts_1_1;
|
|
},
|
|
function (asserts_ts_3_1) {
|
|
asserts_ts_3 = asserts_ts_3_1;
|
|
},
|
|
],
|
|
execute: function () {
|
|
DEFAULT_BUF_SIZE = 4096;
|
|
MIN_BUF_SIZE = 16;
|
|
MAX_CONSECUTIVE_EMPTY_READS = 100;
|
|
CR = util_ts_1.charCode("\r");
|
|
LF = util_ts_1.charCode("\n");
|
|
BufferFullError = class BufferFullError extends Error {
|
|
constructor(partial) {
|
|
super("Buffer full");
|
|
this.partial = partial;
|
|
this.name = "BufferFullError";
|
|
}
|
|
};
|
|
exports_16("BufferFullError", BufferFullError);
|
|
PartialReadError = class PartialReadError
|
|
extends Deno.errors.UnexpectedEof {
|
|
constructor() {
|
|
super("Encountered UnexpectedEof, data only partially read");
|
|
this.name = "PartialReadError";
|
|
}
|
|
};
|
|
exports_16("PartialReadError", PartialReadError);
|
|
/** BufReader implements buffering for a Reader object. */
|
|
BufReader = class BufReader {
|
|
constructor(rd, size = DEFAULT_BUF_SIZE) {
|
|
this.r = 0; // buf read position.
|
|
this.w = 0; // buf write position.
|
|
this.eof = false;
|
|
if (size < MIN_BUF_SIZE) {
|
|
size = MIN_BUF_SIZE;
|
|
}
|
|
this._reset(new Uint8Array(size), rd);
|
|
}
|
|
// private lastByte: number;
|
|
// private lastCharSize: number;
|
|
/** return new BufReader unless r is BufReader */
|
|
static create(r, size = DEFAULT_BUF_SIZE) {
|
|
return r instanceof BufReader ? r : new BufReader(r, size);
|
|
}
|
|
/** Returns the size of the underlying buffer in bytes. */
|
|
size() {
|
|
return this.buf.byteLength;
|
|
}
|
|
buffered() {
|
|
return this.w - this.r;
|
|
}
|
|
// Reads a new chunk into the buffer.
|
|
async _fill() {
|
|
// 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;
|
|
}
|
|
asserts_ts_3.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) {
|
|
this._reset(this.buf, r);
|
|
}
|
|
_reset(buf, rd) {
|
|
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) {
|
|
let rr = 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;
|
|
asserts_ts_3.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;
|
|
}
|
|
asserts_ts_3.assert(rr >= 0, "negative read");
|
|
this.w += rr;
|
|
}
|
|
// copy as much as we can
|
|
const copied = util_ts_1.copyBytes(
|
|
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) {
|
|
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() {
|
|
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) {
|
|
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() {
|
|
let line;
|
|
try {
|
|
line = await this.readSlice(LF);
|
|
} catch (err) {
|
|
let { partial } = err;
|
|
asserts_ts_3.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".
|
|
asserts_ts_3.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) {
|
|
let s = 0; // search start index
|
|
let slice;
|
|
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) {
|
|
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);
|
|
}
|
|
};
|
|
exports_16("BufReader", BufReader);
|
|
AbstractBufBase = class AbstractBufBase {
|
|
constructor() {
|
|
this.usedBufferBytes = 0;
|
|
this.err = null;
|
|
}
|
|
/** Size returns the size of the underlying buffer in bytes. */
|
|
size() {
|
|
return this.buf.byteLength;
|
|
}
|
|
/** Returns how many bytes are unused in the buffer. */
|
|
available() {
|
|
return this.buf.byteLength - this.usedBufferBytes;
|
|
}
|
|
/** buffered returns the number of bytes that have been written into the
|
|
* current buffer.
|
|
*/
|
|
buffered() {
|
|
return this.usedBufferBytes;
|
|
}
|
|
checkBytesWritten(numBytesWritten) {
|
|
if (numBytesWritten < this.usedBufferBytes) {
|
|
if (numBytesWritten > 0) {
|
|
this.buf.copyWithin(0, numBytesWritten, this.usedBufferBytes);
|
|
this.usedBufferBytes -= numBytesWritten;
|
|
}
|
|
this.err = new Error("Short write");
|
|
throw this.err;
|
|
}
|
|
}
|
|
};
|
|
/** 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.
|
|
*/
|
|
BufWriter = class BufWriter extends AbstractBufBase {
|
|
constructor(writer, size = DEFAULT_BUF_SIZE) {
|
|
super();
|
|
this.writer = writer;
|
|
if (size <= 0) {
|
|
size = DEFAULT_BUF_SIZE;
|
|
}
|
|
this.buf = new Uint8Array(size);
|
|
}
|
|
/** return new BufWriter unless writer is BufWriter */
|
|
static create(writer, size = DEFAULT_BUF_SIZE) {
|
|
return writer instanceof BufWriter ? writer
|
|
: new BufWriter(writer, size);
|
|
}
|
|
/** Discards any unflushed buffered data, clears any error, and
|
|
* resets buffer to write its output to w.
|
|
*/
|
|
reset(w) {
|
|
this.err = null;
|
|
this.usedBufferBytes = 0;
|
|
this.writer = w;
|
|
}
|
|
/** Flush writes any buffered data to the underlying io.Writer. */
|
|
async flush() {
|
|
if (this.err !== null) {
|
|
throw this.err;
|
|
}
|
|
if (this.usedBufferBytes === 0) {
|
|
return;
|
|
}
|
|
let numBytesWritten = 0;
|
|
try {
|
|
numBytesWritten = await this.writer.write(
|
|
this.buf.subarray(0, this.usedBufferBytes),
|
|
);
|
|
} catch (e) {
|
|
this.err = e;
|
|
throw e;
|
|
}
|
|
this.checkBytesWritten(numBytesWritten);
|
|
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) {
|
|
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 = util_ts_1.copyBytes(
|
|
data,
|
|
this.buf,
|
|
this.usedBufferBytes,
|
|
);
|
|
this.usedBufferBytes += numBytesWritten;
|
|
await this.flush();
|
|
}
|
|
totalBytesWritten += numBytesWritten;
|
|
data = data.subarray(numBytesWritten);
|
|
}
|
|
numBytesWritten = util_ts_1.copyBytes(
|
|
data,
|
|
this.buf,
|
|
this.usedBufferBytes,
|
|
);
|
|
this.usedBufferBytes += numBytesWritten;
|
|
totalBytesWritten += numBytesWritten;
|
|
return totalBytesWritten;
|
|
}
|
|
};
|
|
exports_16("BufWriter", BufWriter);
|
|
/** 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.
|
|
*/
|
|
BufWriterSync = class BufWriterSync extends AbstractBufBase {
|
|
constructor(writer, size = DEFAULT_BUF_SIZE) {
|
|
super();
|
|
this.writer = writer;
|
|
if (size <= 0) {
|
|
size = DEFAULT_BUF_SIZE;
|
|
}
|
|
this.buf = new Uint8Array(size);
|
|
}
|
|
/** return new BufWriterSync unless writer is BufWriterSync */
|
|
static create(writer, size = DEFAULT_BUF_SIZE) {
|
|
return writer instanceof BufWriterSync
|
|
? writer
|
|
: new BufWriterSync(writer, size);
|
|
}
|
|
/** Discards any unflushed buffered data, clears any error, and
|
|
* resets buffer to write its output to w.
|
|
*/
|
|
reset(w) {
|
|
this.err = null;
|
|
this.usedBufferBytes = 0;
|
|
this.writer = w;
|
|
}
|
|
/** Flush writes any buffered data to the underlying io.WriterSync. */
|
|
flush() {
|
|
if (this.err !== null) {
|
|
throw this.err;
|
|
}
|
|
if (this.usedBufferBytes === 0) {
|
|
return;
|
|
}
|
|
let numBytesWritten = 0;
|
|
try {
|
|
numBytesWritten = this.writer.writeSync(
|
|
this.buf.subarray(0, this.usedBufferBytes),
|
|
);
|
|
} catch (e) {
|
|
this.err = e;
|
|
throw e;
|
|
}
|
|
this.checkBytesWritten(numBytesWritten);
|
|
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) {
|
|
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 = util_ts_1.copyBytes(
|
|
data,
|
|
this.buf,
|
|
this.usedBufferBytes,
|
|
);
|
|
this.usedBufferBytes += numBytesWritten;
|
|
this.flush();
|
|
}
|
|
totalBytesWritten += numBytesWritten;
|
|
data = data.subarray(numBytesWritten);
|
|
}
|
|
numBytesWritten = util_ts_1.copyBytes(
|
|
data,
|
|
this.buf,
|
|
this.usedBufferBytes,
|
|
);
|
|
this.usedBufferBytes += numBytesWritten;
|
|
totalBytesWritten += numBytesWritten;
|
|
return totalBytesWritten;
|
|
}
|
|
};
|
|
exports_16("BufWriterSync", BufWriterSync);
|
|
},
|
|
};
|
|
},
|
|
);
|
|
System.register(
|
|
"https://deno.land/std@0.56.0/async/deferred",
|
|
[],
|
|
function (exports_17, context_17) {
|
|
"use strict";
|
|
var __moduleName = context_17 && context_17.id;
|
|
/** Creates a Promise with the `reject` and `resolve` functions
|
|
* placed as methods on the promise object itself. It allows you to do:
|
|
*
|
|
* const p = deferred<number>();
|
|
* // ...
|
|
* p.resolve(42);
|
|
*/
|
|
function deferred() {
|
|
let methods;
|
|
const promise = new Promise((resolve, reject) => {
|
|
methods = { resolve, reject };
|
|
});
|
|
return Object.assign(promise, methods);
|
|
}
|
|
exports_17("deferred", deferred);
|
|
return {
|
|
setters: [],
|
|
execute: function () {
|
|
},
|
|
};
|
|
},
|
|
);
|
|
System.register(
|
|
"https://deno.land/std@0.56.0/async/delay",
|
|
[],
|
|
function (exports_18, context_18) {
|
|
"use strict";
|
|
var __moduleName = context_18 && context_18.id;
|
|
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
|
/* Resolves after the given number of milliseconds. */
|
|
function delay(ms) {
|
|
return new Promise((res) =>
|
|
setTimeout(() => {
|
|
res();
|
|
}, ms)
|
|
);
|
|
}
|
|
exports_18("delay", delay);
|
|
return {
|
|
setters: [],
|
|
execute: function () {
|
|
},
|
|
};
|
|
},
|
|
);
|
|
System.register(
|
|
"https://deno.land/std@0.56.0/async/mux_async_iterator",
|
|
["https://deno.land/std@0.56.0/async/deferred"],
|
|
function (exports_19, context_19) {
|
|
"use strict";
|
|
var deferred_ts_1, MuxAsyncIterator;
|
|
var __moduleName = context_19 && context_19.id;
|
|
return {
|
|
setters: [
|
|
function (deferred_ts_1_1) {
|
|
deferred_ts_1 = deferred_ts_1_1;
|
|
},
|
|
],
|
|
execute: function () {
|
|
/** The MuxAsyncIterator class multiplexes multiple async iterators into a
|
|
* single stream. It currently makes a few assumptions:
|
|
* - The iterators do not throw.
|
|
* - The final result (the value returned and not yielded from the iterator)
|
|
* does not matter; if there is any, it is discarded.
|
|
*/
|
|
MuxAsyncIterator = class MuxAsyncIterator {
|
|
constructor() {
|
|
this.iteratorCount = 0;
|
|
this.yields = [];
|
|
this.signal = deferred_ts_1.deferred();
|
|
}
|
|
add(iterator) {
|
|
++this.iteratorCount;
|
|
this.callIteratorNext(iterator);
|
|
}
|
|
async callIteratorNext(iterator) {
|
|
const { value, done } = await iterator.next();
|
|
if (done) {
|
|
--this.iteratorCount;
|
|
} else {
|
|
this.yields.push({ iterator, value });
|
|
}
|
|
this.signal.resolve();
|
|
}
|
|
async *iterate() {
|
|
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);
|
|
}
|
|
// Clear the `yields` list and reset the `signal` promise.
|
|
this.yields.length = 0;
|
|
this.signal = deferred_ts_1.deferred();
|
|
}
|
|
}
|
|
[Symbol.asyncIterator]() {
|
|
return this.iterate();
|
|
}
|
|
};
|
|
exports_19("MuxAsyncIterator", MuxAsyncIterator);
|
|
},
|
|
};
|
|
},
|
|
);
|
|
System.register(
|
|
"https://deno.land/std@0.56.0/async/mod",
|
|
[
|
|
"https://deno.land/std@0.56.0/async/deferred",
|
|
"https://deno.land/std@0.56.0/async/delay",
|
|
"https://deno.land/std@0.56.0/async/mux_async_iterator",
|
|
],
|
|
function (exports_20, context_20) {
|
|
"use strict";
|
|
var __moduleName = context_20 && context_20.id;
|
|
function exportStar_2(m) {
|
|
var exports = {};
|
|
for (var n in m) {
|
|
if (n !== "default") exports[n] = m[n];
|
|
}
|
|
exports_20(exports);
|
|
}
|
|
return {
|
|
setters: [
|
|
function (deferred_ts_2_1) {
|
|
exportStar_2(deferred_ts_2_1);
|
|
},
|
|
function (delay_ts_1_1) {
|
|
exportStar_2(delay_ts_1_1);
|
|
},
|
|
function (mux_async_iterator_ts_1_1) {
|
|
exportStar_2(mux_async_iterator_ts_1_1);
|
|
},
|
|
],
|
|
execute: function () {
|
|
},
|
|
};
|
|
},
|
|
);
|
|
System.register(
|
|
"https://deno.land/std@0.56.0/bytes/mod",
|
|
["https://deno.land/std@0.56.0/io/util"],
|
|
function (exports_21, context_21) {
|
|
"use strict";
|
|
var util_ts_2;
|
|
var __moduleName = context_21 && context_21.id;
|
|
/** Find first index of binary pattern from a. If not found, then return -1
|
|
* @param source soruce array
|
|
* @param pat pattern to find in source array
|
|
*/
|
|
function findIndex(source, pat) {
|
|
const s = pat[0];
|
|
for (let i = 0; i < source.length; i++) {
|
|
if (source[i] !== s) {
|
|
continue;
|
|
}
|
|
const pin = i;
|
|
let matched = 1;
|
|
let j = i;
|
|
while (matched < pat.length) {
|
|
j++;
|
|
if (source[j] !== pat[j - pin]) {
|
|
break;
|
|
}
|
|
matched++;
|
|
}
|
|
if (matched === pat.length) {
|
|
return pin;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
exports_21("findIndex", findIndex);
|
|
/** Find last index of binary pattern from a. If not found, then return -1.
|
|
* @param source soruce array
|
|
* @param pat pattern to find in source array
|
|
*/
|
|
function findLastIndex(source, pat) {
|
|
const e = pat[pat.length - 1];
|
|
for (let i = source.length - 1; i >= 0; i--) {
|
|
if (source[i] !== e) {
|
|
continue;
|
|
}
|
|
const pin = i;
|
|
let matched = 1;
|
|
let j = i;
|
|
while (matched < pat.length) {
|
|
j--;
|
|
if (source[j] !== pat[pat.length - 1 - (pin - j)]) {
|
|
break;
|
|
}
|
|
matched++;
|
|
}
|
|
if (matched === pat.length) {
|
|
return pin - pat.length + 1;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
exports_21("findLastIndex", findLastIndex);
|
|
/** Check whether binary arrays are equal to each other.
|
|
* @param source first array to check equality
|
|
* @param match second array to check equality
|
|
*/
|
|
function equal(source, match) {
|
|
if (source.length !== match.length) {
|
|
return false;
|
|
}
|
|
for (let i = 0; i < match.length; i++) {
|
|
if (source[i] !== match[i]) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
exports_21("equal", equal);
|
|
/** Check whether binary array starts with prefix.
|
|
* @param source srouce array
|
|
* @param prefix prefix array to check in source
|
|
*/
|
|
function hasPrefix(source, prefix) {
|
|
for (let i = 0, max = prefix.length; i < max; i++) {
|
|
if (source[i] !== prefix[i]) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
exports_21("hasPrefix", hasPrefix);
|
|
/** Check whether binary array ends with suffix.
|
|
* @param source srouce array
|
|
* @param suffix suffix array to check in source
|
|
*/
|
|
function hasSuffix(source, suffix) {
|
|
for (
|
|
let srci = source.length - 1, sfxi = suffix.length - 1;
|
|
sfxi >= 0;
|
|
srci--, sfxi--
|
|
) {
|
|
if (source[srci] !== suffix[sfxi]) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
exports_21("hasSuffix", hasSuffix);
|
|
/** Repeat bytes. returns a new byte slice consisting of `count` copies of `b`.
|
|
* @param origin The origin bytes
|
|
* @param count The count you want to repeat.
|
|
*/
|
|
function repeat(origin, count) {
|
|
if (count === 0) {
|
|
return new Uint8Array();
|
|
}
|
|
if (count < 0) {
|
|
throw new Error("bytes: negative repeat count");
|
|
} else if ((origin.length * count) / count !== origin.length) {
|
|
throw new Error("bytes: repeat count causes overflow");
|
|
}
|
|
const int = Math.floor(count);
|
|
if (int !== count) {
|
|
throw new Error("bytes: repeat count must be an integer");
|
|
}
|
|
const nb = new Uint8Array(origin.length * count);
|
|
let bp = util_ts_2.copyBytes(origin, nb);
|
|
for (; bp < nb.length; bp *= 2) {
|
|
util_ts_2.copyBytes(nb.slice(0, bp), nb, bp);
|
|
}
|
|
return nb;
|
|
}
|
|
exports_21("repeat", repeat);
|
|
/** Concatenate two binary arrays and return new one.
|
|
* @param origin origin array to concatenate
|
|
* @param b array to concatenate with origin
|
|
*/
|
|
function concat(origin, b) {
|
|
const output = new Uint8Array(origin.length + b.length);
|
|
output.set(origin, 0);
|
|
output.set(b, origin.length);
|
|
return output;
|
|
}
|
|
exports_21("concat", concat);
|
|
/** Check srouce array contains pattern array.
|
|
* @param source srouce array
|
|
* @param pat patter array
|
|
*/
|
|
function contains(source, pat) {
|
|
return findIndex(source, pat) != -1;
|
|
}
|
|
exports_21("contains", contains);
|
|
return {
|
|
setters: [
|
|
function (util_ts_2_1) {
|
|
util_ts_2 = util_ts_2_1;
|
|
},
|
|
],
|
|
execute: function () {
|
|
},
|
|
};
|
|
},
|
|
);
|
|
// Based on https://github.com/golang/go/tree/master/src/net/textproto
|
|
// 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.
|
|
System.register(
|
|
"https://deno.land/std@0.56.0/textproto/mod",
|
|
[
|
|
"https://deno.land/std@0.56.0/io/util",
|
|
"https://deno.land/std@0.56.0/bytes/mod",
|
|
"https://deno.land/std@0.56.0/encoding/utf8",
|
|
],
|
|
function (exports_22, context_22) {
|
|
"use strict";
|
|
var util_ts_3, mod_ts_2, utf8_ts_2, invalidHeaderCharRegex, TextProtoReader;
|
|
var __moduleName = context_22 && context_22.id;
|
|
function str(buf) {
|
|
if (buf == null) {
|
|
return "";
|
|
} else {
|
|
return utf8_ts_2.decode(buf);
|
|
}
|
|
}
|
|
return {
|
|
setters: [
|
|
function (util_ts_3_1) {
|
|
util_ts_3 = util_ts_3_1;
|
|
},
|
|
function (mod_ts_2_1) {
|
|
mod_ts_2 = mod_ts_2_1;
|
|
},
|
|
function (utf8_ts_2_1) {
|
|
utf8_ts_2 = utf8_ts_2_1;
|
|
},
|
|
],
|
|
execute: function () {
|
|
// FROM https://github.com/denoland/deno/blob/b34628a26ab0187a827aa4ebe256e23178e25d39/cli/js/web/headers.ts#L9
|
|
invalidHeaderCharRegex = /[^\t\x20-\x7e\x80-\xff]/g;
|
|
TextProtoReader = class TextProtoReader {
|
|
constructor(r) {
|
|
this.r = r;
|
|
}
|
|
/** readLine() reads a single line from the TextProtoReader,
|
|
* eliding the final \n or \r\n from the returned string.
|
|
*/
|
|
async readLine() {
|
|
const s = await this.readLineSlice();
|
|
if (s === null) {
|
|
return null;
|
|
}
|
|
return str(s);
|
|
}
|
|
/** ReadMIMEHeader reads a MIME-style header from r.
|
|
* The header is a sequence of possibly continued Key: Value lines
|
|
* ending in a blank line.
|
|
* The returned map m maps CanonicalMIMEHeaderKey(key) to a
|
|
* sequence of values in the same order encountered in the input.
|
|
*
|
|
* For example, consider this input:
|
|
*
|
|
* My-Key: Value 1
|
|
* Long-Key: Even
|
|
* Longer Value
|
|
* My-Key: Value 2
|
|
*
|
|
* Given that input, ReadMIMEHeader returns the map:
|
|
*
|
|
* map[string][]string{
|
|
* "My-Key": {"Value 1", "Value 2"},
|
|
* "Long-Key": {"Even Longer Value"},
|
|
* }
|
|
*/
|
|
async readMIMEHeader() {
|
|
const m = new Headers();
|
|
let line;
|
|
// The first line cannot start with a leading space.
|
|
let buf = await this.r.peek(1);
|
|
if (buf === null) {
|
|
return null;
|
|
} else if (
|
|
buf[0] == util_ts_3.charCode(" ") ||
|
|
buf[0] == util_ts_3.charCode("\t")
|
|
) {
|
|
line = (await this.readLineSlice());
|
|
}
|
|
buf = await this.r.peek(1);
|
|
if (buf === null) {
|
|
throw new Deno.errors.UnexpectedEof();
|
|
} else if (
|
|
buf[0] == util_ts_3.charCode(" ") ||
|
|
buf[0] == util_ts_3.charCode("\t")
|
|
) {
|
|
throw new Deno.errors.InvalidData(
|
|
`malformed MIME header initial line: ${str(line)}`,
|
|
);
|
|
}
|
|
while (true) {
|
|
const kv = await this.readLineSlice(); // readContinuedLineSlice
|
|
if (kv === null) {
|
|
throw new Deno.errors.UnexpectedEof();
|
|
}
|
|
if (kv.byteLength === 0) {
|
|
return m;
|
|
}
|
|
// Key ends at first colon
|
|
let i = kv.indexOf(util_ts_3.charCode(":"));
|
|
if (i < 0) {
|
|
throw new Deno.errors.InvalidData(
|
|
`malformed MIME header line: ${str(kv)}`,
|
|
);
|
|
}
|
|
//let key = canonicalMIMEHeaderKey(kv.subarray(0, endKey));
|
|
const key = str(kv.subarray(0, i));
|
|
// As per RFC 7230 field-name is a token,
|
|
// tokens consist of one or more chars.
|
|
// We could throw `Deno.errors.InvalidData` here,
|
|
// but better to be liberal in what we
|
|
// accept, so if we get an empty key, skip it.
|
|
if (key == "") {
|
|
continue;
|
|
}
|
|
// Skip initial spaces in value.
|
|
i++; // skip colon
|
|
while (
|
|
i < kv.byteLength &&
|
|
(kv[i] == util_ts_3.charCode(" ") ||
|
|
kv[i] == util_ts_3.charCode("\t"))
|
|
) {
|
|
i++;
|
|
}
|
|
const value = str(kv.subarray(i)).replace(
|
|
invalidHeaderCharRegex,
|
|
encodeURI,
|
|
);
|
|
// In case of invalid header we swallow the error
|
|
// example: "Audio Mode" => invalid due to space in the key
|
|
try {
|
|
m.append(key, value);
|
|
} catch {}
|
|
}
|
|
}
|
|
async readLineSlice() {
|
|
// this.closeDot();
|
|
let line;
|
|
while (true) {
|
|
const r = await this.r.readLine();
|
|
if (r === null) {
|
|
return null;
|
|
}
|
|
const { line: l, more } = r;
|
|
// Avoid the copy if the first call produced a full line.
|
|
if (!line && !more) {
|
|
// TODO(ry):
|
|
// This skipSpace() is definitely misplaced, but I don't know where it
|
|
// comes from nor how to fix it.
|
|
if (this.skipSpace(l) === 0) {
|
|
return new Uint8Array(0);
|
|
}
|
|
return l;
|
|
}
|
|
line = line ? mod_ts_2.concat(line, l) : l;
|
|
if (!more) {
|
|
break;
|
|
}
|
|
}
|
|
return line;
|
|
}
|
|
skipSpace(l) {
|
|
let n = 0;
|
|
for (let i = 0; i < l.length; i++) {
|
|
if (
|
|
l[i] === util_ts_3.charCode(" ") ||
|
|
l[i] === util_ts_3.charCode("\t")
|
|
) {
|
|
continue;
|
|
}
|
|
n++;
|
|
}
|
|
return n;
|
|
}
|
|
};
|
|
exports_22("TextProtoReader", TextProtoReader);
|
|
},
|
|
};
|
|
},
|
|
);
|
|
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
|
System.register(
|
|
"https://deno.land/std@0.56.0/http/http_status",
|
|
[],
|
|
function (exports_23, context_23) {
|
|
"use strict";
|
|
var Status, STATUS_TEXT;
|
|
var __moduleName = context_23 && context_23.id;
|
|
return {
|
|
setters: [],
|
|
execute: function () {
|
|
/** HTTP status codes */
|
|
(function (Status) {
|
|
/** RFC 7231, 6.2.1 */
|
|
Status[Status["Continue"] = 100] = "Continue";
|
|
/** RFC 7231, 6.2.2 */
|
|
Status[Status["SwitchingProtocols"] = 101] = "SwitchingProtocols";
|
|
/** RFC 2518, 10.1 */
|
|
Status[Status["Processing"] = 102] = "Processing";
|
|
/** RFC 8297 **/
|
|
Status[Status["EarlyHints"] = 103] = "EarlyHints";
|
|
/** RFC 7231, 6.3.1 */
|
|
Status[Status["OK"] = 200] = "OK";
|
|
/** RFC 7231, 6.3.2 */
|
|
Status[Status["Created"] = 201] = "Created";
|
|
/** RFC 7231, 6.3.3 */
|
|
Status[Status["Accepted"] = 202] = "Accepted";
|
|
/** RFC 7231, 6.3.4 */
|
|
Status[Status["NonAuthoritativeInfo"] = 203] = "NonAuthoritativeInfo";
|
|
/** RFC 7231, 6.3.5 */
|
|
Status[Status["NoContent"] = 204] = "NoContent";
|
|
/** RFC 7231, 6.3.6 */
|
|
Status[Status["ResetContent"] = 205] = "ResetContent";
|
|
/** RFC 7233, 4.1 */
|
|
Status[Status["PartialContent"] = 206] = "PartialContent";
|
|
/** RFC 4918, 11.1 */
|
|
Status[Status["MultiStatus"] = 207] = "MultiStatus";
|
|
/** RFC 5842, 7.1 */
|
|
Status[Status["AlreadyReported"] = 208] = "AlreadyReported";
|
|
/** RFC 3229, 10.4.1 */
|
|
Status[Status["IMUsed"] = 226] = "IMUsed";
|
|
/** RFC 7231, 6.4.1 */
|
|
Status[Status["MultipleChoices"] = 300] = "MultipleChoices";
|
|
/** RFC 7231, 6.4.2 */
|
|
Status[Status["MovedPermanently"] = 301] = "MovedPermanently";
|
|
/** RFC 7231, 6.4.3 */
|
|
Status[Status["Found"] = 302] = "Found";
|
|
/** RFC 7231, 6.4.4 */
|
|
Status[Status["SeeOther"] = 303] = "SeeOther";
|
|
/** RFC 7232, 4.1 */
|
|
Status[Status["NotModified"] = 304] = "NotModified";
|
|
/** RFC 7231, 6.4.5 */
|
|
Status[Status["UseProxy"] = 305] = "UseProxy";
|
|
/** RFC 7231, 6.4.7 */
|
|
Status[Status["TemporaryRedirect"] = 307] = "TemporaryRedirect";
|
|
/** RFC 7538, 3 */
|
|
Status[Status["PermanentRedirect"] = 308] = "PermanentRedirect";
|
|
/** RFC 7231, 6.5.1 */
|
|
Status[Status["BadRequest"] = 400] = "BadRequest";
|
|
/** RFC 7235, 3.1 */
|
|
Status[Status["Unauthorized"] = 401] = "Unauthorized";
|
|
/** RFC 7231, 6.5.2 */
|
|
Status[Status["PaymentRequired"] = 402] = "PaymentRequired";
|
|
/** RFC 7231, 6.5.3 */
|
|
Status[Status["Forbidden"] = 403] = "Forbidden";
|
|
/** RFC 7231, 6.5.4 */
|
|
Status[Status["NotFound"] = 404] = "NotFound";
|
|
/** RFC 7231, 6.5.5 */
|
|
Status[Status["MethodNotAllowed"] = 405] = "MethodNotAllowed";
|
|
/** RFC 7231, 6.5.6 */
|
|
Status[Status["NotAcceptable"] = 406] = "NotAcceptable";
|
|
/** RFC 7235, 3.2 */
|
|
Status[Status["ProxyAuthRequired"] = 407] = "ProxyAuthRequired";
|
|
/** RFC 7231, 6.5.7 */
|
|
Status[Status["RequestTimeout"] = 408] = "RequestTimeout";
|
|
/** RFC 7231, 6.5.8 */
|
|
Status[Status["Conflict"] = 409] = "Conflict";
|
|
/** RFC 7231, 6.5.9 */
|
|
Status[Status["Gone"] = 410] = "Gone";
|
|
/** RFC 7231, 6.5.10 */
|
|
Status[Status["LengthRequired"] = 411] = "LengthRequired";
|
|
/** RFC 7232, 4.2 */
|
|
Status[Status["PreconditionFailed"] = 412] = "PreconditionFailed";
|
|
/** RFC 7231, 6.5.11 */
|
|
Status[Status["RequestEntityTooLarge"] = 413] =
|
|
"RequestEntityTooLarge";
|
|
/** RFC 7231, 6.5.12 */
|
|
Status[Status["RequestURITooLong"] = 414] = "RequestURITooLong";
|
|
/** RFC 7231, 6.5.13 */
|
|
Status[Status["UnsupportedMediaType"] = 415] = "UnsupportedMediaType";
|
|
/** RFC 7233, 4.4 */
|
|
Status[Status["RequestedRangeNotSatisfiable"] = 416] =
|
|
"RequestedRangeNotSatisfiable";
|
|
/** RFC 7231, 6.5.14 */
|
|
Status[Status["ExpectationFailed"] = 417] = "ExpectationFailed";
|
|
/** RFC 7168, 2.3.3 */
|
|
Status[Status["Teapot"] = 418] = "Teapot";
|
|
/** RFC 7540, 9.1.2 */
|
|
Status[Status["MisdirectedRequest"] = 421] = "MisdirectedRequest";
|
|
/** RFC 4918, 11.2 */
|
|
Status[Status["UnprocessableEntity"] = 422] = "UnprocessableEntity";
|
|
/** RFC 4918, 11.3 */
|
|
Status[Status["Locked"] = 423] = "Locked";
|
|
/** RFC 4918, 11.4 */
|
|
Status[Status["FailedDependency"] = 424] = "FailedDependency";
|
|
/** RFC 8470, 5.2 */
|
|
Status[Status["TooEarly"] = 425] = "TooEarly";
|
|
/** RFC 7231, 6.5.15 */
|
|
Status[Status["UpgradeRequired"] = 426] = "UpgradeRequired";
|
|
/** RFC 6585, 3 */
|
|
Status[Status["PreconditionRequired"] = 428] = "PreconditionRequired";
|
|
/** RFC 6585, 4 */
|
|
Status[Status["TooManyRequests"] = 429] = "TooManyRequests";
|
|
/** RFC 6585, 5 */
|
|
Status[Status["RequestHeaderFieldsTooLarge"] = 431] =
|
|
"RequestHeaderFieldsTooLarge";
|
|
/** RFC 7725, 3 */
|
|
Status[Status["UnavailableForLegalReasons"] = 451] =
|
|
"UnavailableForLegalReasons";
|
|
/** RFC 7231, 6.6.1 */
|
|
Status[Status["InternalServerError"] = 500] = "InternalServerError";
|
|
/** RFC 7231, 6.6.2 */
|
|
Status[Status["NotImplemented"] = 501] = "NotImplemented";
|
|
/** RFC 7231, 6.6.3 */
|
|
Status[Status["BadGateway"] = 502] = "BadGateway";
|
|
/** RFC 7231, 6.6.4 */
|
|
Status[Status["ServiceUnavailable"] = 503] = "ServiceUnavailable";
|
|
/** RFC 7231, 6.6.5 */
|
|
Status[Status["GatewayTimeout"] = 504] = "GatewayTimeout";
|
|
/** RFC 7231, 6.6.6 */
|
|
Status[Status["HTTPVersionNotSupported"] = 505] =
|
|
"HTTPVersionNotSupported";
|
|
/** RFC 2295, 8.1 */
|
|
Status[Status["VariantAlsoNegotiates"] = 506] =
|
|
"VariantAlsoNegotiates";
|
|
/** RFC 4918, 11.5 */
|
|
Status[Status["InsufficientStorage"] = 507] = "InsufficientStorage";
|
|
/** RFC 5842, 7.2 */
|
|
Status[Status["LoopDetected"] = 508] = "LoopDetected";
|
|
/** RFC 2774, 7 */
|
|
Status[Status["NotExtended"] = 510] = "NotExtended";
|
|
/** RFC 6585, 6 */
|
|
Status[Status["NetworkAuthenticationRequired"] = 511] =
|
|
"NetworkAuthenticationRequired";
|
|
})(Status || (Status = {}));
|
|
exports_23("Status", Status);
|
|
exports_23(
|
|
"STATUS_TEXT",
|
|
STATUS_TEXT = new Map([
|
|
[Status.Continue, "Continue"],
|
|
[Status.SwitchingProtocols, "Switching Protocols"],
|
|
[Status.Processing, "Processing"],
|
|
[Status.EarlyHints, "Early Hints"],
|
|
[Status.OK, "OK"],
|
|
[Status.Created, "Created"],
|
|
[Status.Accepted, "Accepted"],
|
|
[Status.NonAuthoritativeInfo, "Non-Authoritative Information"],
|
|
[Status.NoContent, "No Content"],
|
|
[Status.ResetContent, "Reset Content"],
|
|
[Status.PartialContent, "Partial Content"],
|
|
[Status.MultiStatus, "Multi-Status"],
|
|
[Status.AlreadyReported, "Already Reported"],
|
|
[Status.IMUsed, "IM Used"],
|
|
[Status.MultipleChoices, "Multiple Choices"],
|
|
[Status.MovedPermanently, "Moved Permanently"],
|
|
[Status.Found, "Found"],
|
|
[Status.SeeOther, "See Other"],
|
|
[Status.NotModified, "Not Modified"],
|
|
[Status.UseProxy, "Use Proxy"],
|
|
[Status.TemporaryRedirect, "Temporary Redirect"],
|
|
[Status.PermanentRedirect, "Permanent Redirect"],
|
|
[Status.BadRequest, "Bad Request"],
|
|
[Status.Unauthorized, "Unauthorized"],
|
|
[Status.PaymentRequired, "Payment Required"],
|
|
[Status.Forbidden, "Forbidden"],
|
|
[Status.NotFound, "Not Found"],
|
|
[Status.MethodNotAllowed, "Method Not Allowed"],
|
|
[Status.NotAcceptable, "Not Acceptable"],
|
|
[Status.ProxyAuthRequired, "Proxy Authentication Required"],
|
|
[Status.RequestTimeout, "Request Timeout"],
|
|
[Status.Conflict, "Conflict"],
|
|
[Status.Gone, "Gone"],
|
|
[Status.LengthRequired, "Length Required"],
|
|
[Status.PreconditionFailed, "Precondition Failed"],
|
|
[Status.RequestEntityTooLarge, "Request Entity Too Large"],
|
|
[Status.RequestURITooLong, "Request URI Too Long"],
|
|
[Status.UnsupportedMediaType, "Unsupported Media Type"],
|
|
[
|
|
Status.RequestedRangeNotSatisfiable,
|
|
"Requested Range Not Satisfiable",
|
|
],
|
|
[Status.ExpectationFailed, "Expectation Failed"],
|
|
[Status.Teapot, "I'm a teapot"],
|
|
[Status.MisdirectedRequest, "Misdirected Request"],
|
|
[Status.UnprocessableEntity, "Unprocessable Entity"],
|
|
[Status.Locked, "Locked"],
|
|
[Status.FailedDependency, "Failed Dependency"],
|
|
[Status.TooEarly, "Too Early"],
|
|
[Status.UpgradeRequired, "Upgrade Required"],
|
|
[Status.PreconditionRequired, "Precondition Required"],
|
|
[Status.TooManyRequests, "Too Many Requests"],
|
|
[
|
|
Status.RequestHeaderFieldsTooLarge,
|
|
"Request Header Fields Too Large",
|
|
],
|
|
[
|
|
Status.UnavailableForLegalReasons,
|
|
"Unavailable For Legal Reasons",
|
|
],
|
|
[Status.InternalServerError, "Internal Server Error"],
|
|
[Status.NotImplemented, "Not Implemented"],
|
|
[Status.BadGateway, "Bad Gateway"],
|
|
[Status.ServiceUnavailable, "Service Unavailable"],
|
|
[Status.GatewayTimeout, "Gateway Timeout"],
|
|
[Status.HTTPVersionNotSupported, "HTTP Version Not Supported"],
|
|
[Status.VariantAlsoNegotiates, "Variant Also Negotiates"],
|
|
[Status.InsufficientStorage, "Insufficient Storage"],
|
|
[Status.LoopDetected, "Loop Detected"],
|
|
[Status.NotExtended, "Not Extended"],
|
|
[
|
|
Status.NetworkAuthenticationRequired,
|
|
"Network Authentication Required",
|
|
],
|
|
]),
|
|
);
|
|
},
|
|
};
|
|
},
|
|
);
|
|
System.register(
|
|
"https://deno.land/std@0.56.0/http/_io",
|
|
[
|
|
"https://deno.land/std@0.56.0/io/bufio",
|
|
"https://deno.land/std@0.56.0/textproto/mod",
|
|
"https://deno.land/std@0.56.0/testing/asserts",
|
|
"https://deno.land/std@0.56.0/encoding/utf8",
|
|
"https://deno.land/std@0.56.0/http/server",
|
|
"https://deno.land/std@0.56.0/http/http_status",
|
|
],
|
|
function (exports_24, context_24) {
|
|
"use strict";
|
|
var bufio_ts_1,
|
|
mod_ts_3,
|
|
asserts_ts_4,
|
|
utf8_ts_3,
|
|
server_ts_1,
|
|
http_status_ts_1;
|
|
var __moduleName = context_24 && context_24.id;
|
|
function emptyReader() {
|
|
return {
|
|
read(_) {
|
|
return Promise.resolve(null);
|
|
},
|
|
};
|
|
}
|
|
exports_24("emptyReader", emptyReader);
|
|
function bodyReader(contentLength, r) {
|
|
let totalRead = 0;
|
|
let finished = false;
|
|
async function read(buf) {
|
|
if (finished) {
|
|
return null;
|
|
}
|
|
let result;
|
|
const remaining = contentLength - totalRead;
|
|
if (remaining >= buf.byteLength) {
|
|
result = await r.read(buf);
|
|
} else {
|
|
const readBuf = buf.subarray(0, remaining);
|
|
result = await r.read(readBuf);
|
|
}
|
|
if (result !== null) {
|
|
totalRead += result;
|
|
}
|
|
finished = totalRead === contentLength;
|
|
return result;
|
|
}
|
|
return { read };
|
|
}
|
|
exports_24("bodyReader", bodyReader);
|
|
function chunkedBodyReader(h, r) {
|
|
// Based on https://tools.ietf.org/html/rfc2616#section-19.4.6
|
|
const tp = new mod_ts_3.TextProtoReader(r);
|
|
let finished = false;
|
|
const chunks = [];
|
|
async function read(buf) {
|
|
if (finished) {
|
|
return null;
|
|
}
|
|
const [chunk] = chunks;
|
|
if (chunk) {
|
|
const chunkRemaining = chunk.data.byteLength - chunk.offset;
|
|
const readLength = Math.min(chunkRemaining, buf.byteLength);
|
|
for (let i = 0; i < readLength; i++) {
|
|
buf[i] = chunk.data[chunk.offset + i];
|
|
}
|
|
chunk.offset += readLength;
|
|
if (chunk.offset === chunk.data.byteLength) {
|
|
chunks.shift();
|
|
// Consume \r\n;
|
|
if ((await tp.readLine()) === null) {
|
|
throw new Deno.errors.UnexpectedEof();
|
|
}
|
|
}
|
|
return readLength;
|
|
}
|
|
const line = await tp.readLine();
|
|
if (line === null) {
|
|
throw new Deno.errors.UnexpectedEof();
|
|
}
|
|
// TODO: handle chunk extension
|
|
const [chunkSizeString] = line.split(";");
|
|
const chunkSize = parseInt(chunkSizeString, 16);
|
|
if (Number.isNaN(chunkSize) || chunkSize < 0) {
|
|
throw new Error("Invalid chunk size");
|
|
}
|
|
if (chunkSize > 0) {
|
|
if (chunkSize > buf.byteLength) {
|
|
let eof = await r.readFull(buf);
|
|
if (eof === null) {
|
|
throw new Deno.errors.UnexpectedEof();
|
|
}
|
|
const restChunk = new Uint8Array(chunkSize - buf.byteLength);
|
|
eof = await r.readFull(restChunk);
|
|
if (eof === null) {
|
|
throw new Deno.errors.UnexpectedEof();
|
|
} else {
|
|
chunks.push({
|
|
offset: 0,
|
|
data: restChunk,
|
|
});
|
|
}
|
|
return buf.byteLength;
|
|
} else {
|
|
const bufToFill = buf.subarray(0, chunkSize);
|
|
const eof = await r.readFull(bufToFill);
|
|
if (eof === null) {
|
|
throw new Deno.errors.UnexpectedEof();
|
|
}
|
|
// Consume \r\n
|
|
if ((await tp.readLine()) === null) {
|
|
throw new Deno.errors.UnexpectedEof();
|
|
}
|
|
return chunkSize;
|
|
}
|
|
} else {
|
|
asserts_ts_4.assert(chunkSize === 0);
|
|
// Consume \r\n
|
|
if ((await r.readLine()) === null) {
|
|
throw new Deno.errors.UnexpectedEof();
|
|
}
|
|
await readTrailers(h, r);
|
|
finished = true;
|
|
return null;
|
|
}
|
|
}
|
|
return { read };
|
|
}
|
|
exports_24("chunkedBodyReader", chunkedBodyReader);
|
|
function isProhibidedForTrailer(key) {
|
|
const s = new Set(["transfer-encoding", "content-length", "trailer"]);
|
|
return s.has(key.toLowerCase());
|
|
}
|
|
/**
|
|
* Read trailer headers from reader and append values to headers.
|
|
* "trailer" field will be deleted.
|
|
* */
|
|
async function readTrailers(headers, r) {
|
|
const headerKeys = parseTrailer(headers.get("trailer"));
|
|
if (!headerKeys) {
|
|
return;
|
|
}
|
|
const tp = new mod_ts_3.TextProtoReader(r);
|
|
const result = await tp.readMIMEHeader();
|
|
asserts_ts_4.assert(result !== null, "trailer must be set");
|
|
for (const [k, v] of result) {
|
|
if (!headerKeys.has(k)) {
|
|
throw new Error("Undeclared trailer field");
|
|
}
|
|
headerKeys.delete(k);
|
|
headers.append(k, v);
|
|
}
|
|
asserts_ts_4.assert(
|
|
Array.from(headerKeys).length === 0,
|
|
"Missing trailers",
|
|
);
|
|
headers.delete("trailer");
|
|
}
|
|
exports_24("readTrailers", readTrailers);
|
|
function parseTrailer(field) {
|
|
if (field == null) {
|
|
return undefined;
|
|
}
|
|
const keys = field.split(",").map((v) => v.trim().toLowerCase());
|
|
if (keys.length === 0) {
|
|
throw new Error("Empty trailer");
|
|
}
|
|
for (const key of keys) {
|
|
if (isProhibidedForTrailer(key)) {
|
|
throw new Error(`Prohibited field for trailer`);
|
|
}
|
|
}
|
|
return new Headers(keys.map((key) => [key, ""]));
|
|
}
|
|
async function writeChunkedBody(w, r) {
|
|
const writer = bufio_ts_1.BufWriter.create(w);
|
|
for await (const chunk of Deno.iter(r)) {
|
|
if (chunk.byteLength <= 0) {
|
|
continue;
|
|
}
|
|
const start = utf8_ts_3.encoder.encode(
|
|
`${chunk.byteLength.toString(16)}\r\n`,
|
|
);
|
|
const end = utf8_ts_3.encoder.encode("\r\n");
|
|
await writer.write(start);
|
|
await writer.write(chunk);
|
|
await writer.write(end);
|
|
}
|
|
const endChunk = utf8_ts_3.encoder.encode("0\r\n\r\n");
|
|
await writer.write(endChunk);
|
|
}
|
|
exports_24("writeChunkedBody", writeChunkedBody);
|
|
/** write trailer headers to writer. it mostly should be called after writeResponse */
|
|
async function writeTrailers(w, headers, trailers) {
|
|
const trailer = headers.get("trailer");
|
|
if (trailer === null) {
|
|
throw new Error('response headers must have "trailer" header field');
|
|
}
|
|
const transferEncoding = headers.get("transfer-encoding");
|
|
if (transferEncoding === null || !transferEncoding.match(/^chunked/)) {
|
|
throw new Error(
|
|
`trailer headers is only allowed for "transfer-encoding: chunked": got "${transferEncoding}"`,
|
|
);
|
|
}
|
|
const writer = bufio_ts_1.BufWriter.create(w);
|
|
const trailerHeaderFields = trailer
|
|
.split(",")
|
|
.map((s) => s.trim().toLowerCase());
|
|
for (const f of trailerHeaderFields) {
|
|
asserts_ts_4.assert(
|
|
!isProhibidedForTrailer(f),
|
|
`"${f}" is prohibited for trailer header`,
|
|
);
|
|
}
|
|
for (const [key, value] of trailers) {
|
|
asserts_ts_4.assert(
|
|
trailerHeaderFields.includes(key),
|
|
`Not trailer header field: ${key}`,
|
|
);
|
|
await writer.write(utf8_ts_3.encoder.encode(`${key}: ${value}\r\n`));
|
|
}
|
|
await writer.write(utf8_ts_3.encoder.encode("\r\n"));
|
|
await writer.flush();
|
|
}
|
|
exports_24("writeTrailers", writeTrailers);
|
|
async function writeResponse(w, r) {
|
|
const protoMajor = 1;
|
|
const protoMinor = 1;
|
|
const statusCode = r.status || 200;
|
|
const statusText = http_status_ts_1.STATUS_TEXT.get(statusCode);
|
|
const writer = bufio_ts_1.BufWriter.create(w);
|
|
if (!statusText) {
|
|
throw new Deno.errors.InvalidData("Bad status code");
|
|
}
|
|
if (!r.body) {
|
|
r.body = new Uint8Array();
|
|
}
|
|
if (typeof r.body === "string") {
|
|
r.body = utf8_ts_3.encoder.encode(r.body);
|
|
}
|
|
let out =
|
|
`HTTP/${protoMajor}.${protoMinor} ${statusCode} ${statusText}\r\n`;
|
|
const headers = r.headers ?? new Headers();
|
|
if (r.body && !headers.get("content-length")) {
|
|
if (r.body instanceof Uint8Array) {
|
|
out += `content-length: ${r.body.byteLength}\r\n`;
|
|
} else if (!headers.get("transfer-encoding")) {
|
|
out += "transfer-encoding: chunked\r\n";
|
|
}
|
|
}
|
|
for (const [key, value] of headers) {
|
|
out += `${key}: ${value}\r\n`;
|
|
}
|
|
out += `\r\n`;
|
|
const header = utf8_ts_3.encoder.encode(out);
|
|
const n = await writer.write(header);
|
|
asserts_ts_4.assert(n === header.byteLength);
|
|
if (r.body instanceof Uint8Array) {
|
|
const n = await writer.write(r.body);
|
|
asserts_ts_4.assert(n === r.body.byteLength);
|
|
} else if (headers.has("content-length")) {
|
|
const contentLength = headers.get("content-length");
|
|
asserts_ts_4.assert(contentLength != null);
|
|
const bodyLength = parseInt(contentLength);
|
|
const n = await Deno.copy(r.body, writer);
|
|
asserts_ts_4.assert(n === bodyLength);
|
|
} else {
|
|
await writeChunkedBody(writer, r.body);
|
|
}
|
|
if (r.trailers) {
|
|
const t = await r.trailers();
|
|
await writeTrailers(writer, headers, t);
|
|
}
|
|
await writer.flush();
|
|
}
|
|
exports_24("writeResponse", writeResponse);
|
|
/**
|
|
* ParseHTTPVersion parses a HTTP version string.
|
|
* "HTTP/1.0" returns (1, 0).
|
|
* Ported from https://github.com/golang/go/blob/f5c43b9/src/net/http/request.go#L766-L792
|
|
*/
|
|
function parseHTTPVersion(vers) {
|
|
switch (vers) {
|
|
case "HTTP/1.1":
|
|
return [1, 1];
|
|
case "HTTP/1.0":
|
|
return [1, 0];
|
|
default: {
|
|
const Big = 1000000; // arbitrary upper bound
|
|
if (!vers.startsWith("HTTP/")) {
|
|
break;
|
|
}
|
|
const dot = vers.indexOf(".");
|
|
if (dot < 0) {
|
|
break;
|
|
}
|
|
const majorStr = vers.substring(vers.indexOf("/") + 1, dot);
|
|
const major = Number(majorStr);
|
|
if (!Number.isInteger(major) || major < 0 || major > Big) {
|
|
break;
|
|
}
|
|
const minorStr = vers.substring(dot + 1);
|
|
const minor = Number(minorStr);
|
|
if (!Number.isInteger(minor) || minor < 0 || minor > Big) {
|
|
break;
|
|
}
|
|
return [major, minor];
|
|
}
|
|
}
|
|
throw new Error(`malformed HTTP version ${vers}`);
|
|
}
|
|
exports_24("parseHTTPVersion", parseHTTPVersion);
|
|
async function readRequest(conn, bufr) {
|
|
const tp = new mod_ts_3.TextProtoReader(bufr);
|
|
const firstLine = await tp.readLine(); // e.g. GET /index.html HTTP/1.0
|
|
if (firstLine === null) {
|
|
return null;
|
|
}
|
|
const headers = await tp.readMIMEHeader();
|
|
if (headers === null) {
|
|
throw new Deno.errors.UnexpectedEof();
|
|
}
|
|
const req = new server_ts_1.ServerRequest();
|
|
req.conn = conn;
|
|
req.r = bufr;
|
|
[req.method, req.url, req.proto] = firstLine.split(" ", 3);
|
|
[req.protoMinor, req.protoMajor] = parseHTTPVersion(req.proto);
|
|
req.headers = headers;
|
|
fixLength(req);
|
|
return req;
|
|
}
|
|
exports_24("readRequest", readRequest);
|
|
function fixLength(req) {
|
|
const contentLength = req.headers.get("Content-Length");
|
|
if (contentLength) {
|
|
const arrClen = contentLength.split(",");
|
|
if (arrClen.length > 1) {
|
|
const distinct = [...new Set(arrClen.map((e) => e.trim()))];
|
|
if (distinct.length > 1) {
|
|
throw Error("cannot contain multiple Content-Length headers");
|
|
} else {
|
|
req.headers.set("Content-Length", distinct[0]);
|
|
}
|
|
}
|
|
const c = req.headers.get("Content-Length");
|
|
if (req.method === "HEAD" && c && c !== "0") {
|
|
throw Error("http: method cannot contain a Content-Length");
|
|
}
|
|
if (c && req.headers.has("transfer-encoding")) {
|
|
// A sender MUST NOT send a Content-Length header field in any message
|
|
// that contains a Transfer-Encoding header field.
|
|
// rfc: https://tools.ietf.org/html/rfc7230#section-3.3.2
|
|
throw new Error(
|
|
"http: Transfer-Encoding and Content-Length cannot be send together",
|
|
);
|
|
}
|
|
}
|
|
}
|
|
return {
|
|
setters: [
|
|
function (bufio_ts_1_1) {
|
|
bufio_ts_1 = bufio_ts_1_1;
|
|
},
|
|
function (mod_ts_3_1) {
|
|
mod_ts_3 = mod_ts_3_1;
|
|
},
|
|
function (asserts_ts_4_1) {
|
|
asserts_ts_4 = asserts_ts_4_1;
|
|
},
|
|
function (utf8_ts_3_1) {
|
|
utf8_ts_3 = utf8_ts_3_1;
|
|
},
|
|
function (server_ts_1_1) {
|
|
server_ts_1 = server_ts_1_1;
|
|
},
|
|
function (http_status_ts_1_1) {
|
|
http_status_ts_1 = http_status_ts_1_1;
|
|
},
|
|
],
|
|
execute: function () {
|
|
},
|
|
};
|
|
},
|
|
);
|
|
System.register(
|
|
"https://deno.land/std@0.56.0/http/server",
|
|
[
|
|
"https://deno.land/std@0.56.0/encoding/utf8",
|
|
"https://deno.land/std@0.56.0/io/bufio",
|
|
"https://deno.land/std@0.56.0/testing/asserts",
|
|
"https://deno.land/std@0.56.0/async/mod",
|
|
"https://deno.land/std@0.56.0/http/_io",
|
|
],
|
|
function (exports_25, context_25) {
|
|
"use strict";
|
|
var utf8_ts_4,
|
|
bufio_ts_2,
|
|
asserts_ts_5,
|
|
mod_ts_4,
|
|
_io_ts_1,
|
|
listen,
|
|
listenTls,
|
|
ServerRequest,
|
|
Server;
|
|
var __moduleName = context_25 && context_25.id;
|
|
/**
|
|
* Create a HTTP server
|
|
*
|
|
* import { serve } from "https://deno.land/std/http/server.ts";
|
|
* const body = "Hello World\n";
|
|
* const server = serve({ port: 8000 });
|
|
* for await (const req of server) {
|
|
* req.respond({ body });
|
|
* }
|
|
*/
|
|
function serve(addr) {
|
|
if (typeof addr === "string") {
|
|
const [hostname, port] = addr.split(":");
|
|
addr = { hostname, port: Number(port) };
|
|
}
|
|
const listener = listen(addr);
|
|
return new Server(listener);
|
|
}
|
|
exports_25("serve", serve);
|
|
/**
|
|
* Start an HTTP server with given options and request handler
|
|
*
|
|
* const body = "Hello World\n";
|
|
* const options = { port: 8000 };
|
|
* listenAndServe(options, (req) => {
|
|
* req.respond({ body });
|
|
* });
|
|
*
|
|
* @param options Server configuration
|
|
* @param handler Request handler
|
|
*/
|
|
async function listenAndServe(addr, handler) {
|
|
const server = serve(addr);
|
|
for await (const request of server) {
|
|
handler(request);
|
|
}
|
|
}
|
|
exports_25("listenAndServe", listenAndServe);
|
|
/**
|
|
* Create an HTTPS server with given options
|
|
*
|
|
* const body = "Hello HTTPS";
|
|
* const options = {
|
|
* hostname: "localhost",
|
|
* port: 443,
|
|
* certFile: "./path/to/localhost.crt",
|
|
* keyFile: "./path/to/localhost.key",
|
|
* };
|
|
* for await (const req of serveTLS(options)) {
|
|
* req.respond({ body });
|
|
* }
|
|
*
|
|
* @param options Server configuration
|
|
* @return Async iterable server instance for incoming requests
|
|
*/
|
|
function serveTLS(options) {
|
|
const tlsOptions = {
|
|
...options,
|
|
transport: "tcp",
|
|
};
|
|
const listener = listenTls(tlsOptions);
|
|
return new Server(listener);
|
|
}
|
|
exports_25("serveTLS", serveTLS);
|
|
/**
|
|
* Start an HTTPS server with given options and request handler
|
|
*
|
|
* const body = "Hello HTTPS";
|
|
* const options = {
|
|
* hostname: "localhost",
|
|
* port: 443,
|
|
* certFile: "./path/to/localhost.crt",
|
|
* keyFile: "./path/to/localhost.key",
|
|
* };
|
|
* listenAndServeTLS(options, (req) => {
|
|
* req.respond({ body });
|
|
* });
|
|
*
|
|
* @param options Server configuration
|
|
* @param handler Request handler
|
|
*/
|
|
async function listenAndServeTLS(options, handler) {
|
|
const server = serveTLS(options);
|
|
for await (const request of server) {
|
|
handler(request);
|
|
}
|
|
}
|
|
exports_25("listenAndServeTLS", listenAndServeTLS);
|
|
return {
|
|
setters: [
|
|
function (utf8_ts_4_1) {
|
|
utf8_ts_4 = utf8_ts_4_1;
|
|
},
|
|
function (bufio_ts_2_1) {
|
|
bufio_ts_2 = bufio_ts_2_1;
|
|
},
|
|
function (asserts_ts_5_1) {
|
|
asserts_ts_5 = asserts_ts_5_1;
|
|
},
|
|
function (mod_ts_4_1) {
|
|
mod_ts_4 = mod_ts_4_1;
|
|
},
|
|
function (_io_ts_1_1) {
|
|
_io_ts_1 = _io_ts_1_1;
|
|
},
|
|
],
|
|
execute: function () {
|
|
listen = Deno.listen, listenTls = Deno.listenTls;
|
|
ServerRequest = class ServerRequest {
|
|
constructor() {
|
|
this.done = mod_ts_4.deferred();
|
|
this._contentLength = undefined;
|
|
this._body = null;
|
|
this.finalized = false;
|
|
}
|
|
/**
|
|
* Value of Content-Length header.
|
|
* If null, then content length is invalid or not given (e.g. chunked encoding).
|
|
*/
|
|
get contentLength() {
|
|
// undefined means not cached.
|
|
// null means invalid or not provided.
|
|
if (this._contentLength === undefined) {
|
|
const cl = this.headers.get("content-length");
|
|
if (cl) {
|
|
this._contentLength = parseInt(cl);
|
|
// Convert NaN to null (as NaN harder to test)
|
|
if (Number.isNaN(this._contentLength)) {
|
|
this._contentLength = null;
|
|
}
|
|
} else {
|
|
this._contentLength = null;
|
|
}
|
|
}
|
|
return this._contentLength;
|
|
}
|
|
/**
|
|
* Body of the request. The easiest way to consume the body is:
|
|
*
|
|
* const buf: Uint8Array = await Deno.readAll(req.body);
|
|
*/
|
|
get body() {
|
|
if (!this._body) {
|
|
if (this.contentLength != null) {
|
|
this._body = _io_ts_1.bodyReader(this.contentLength, this.r);
|
|
} else {
|
|
const transferEncoding = this.headers.get("transfer-encoding");
|
|
if (transferEncoding != null) {
|
|
const parts = transferEncoding
|
|
.split(",")
|
|
.map((e) => e.trim().toLowerCase());
|
|
asserts_ts_5.assert(
|
|
parts.includes("chunked"),
|
|
'transfer-encoding must include "chunked" if content-length is not set',
|
|
);
|
|
this._body = _io_ts_1.chunkedBodyReader(this.headers, this.r);
|
|
} else {
|
|
// Neither content-length nor transfer-encoding: chunked
|
|
this._body = _io_ts_1.emptyReader();
|
|
}
|
|
}
|
|
}
|
|
return this._body;
|
|
}
|
|
async respond(r) {
|
|
let err;
|
|
try {
|
|
// Write our response!
|
|
await _io_ts_1.writeResponse(this.w, r);
|
|
} catch (e) {
|
|
try {
|
|
// Eagerly close on error.
|
|
this.conn.close();
|
|
} catch {}
|
|
err = e;
|
|
}
|
|
// Signal that this request has been processed and the next pipelined
|
|
// request on the same connection can be accepted.
|
|
this.done.resolve(err);
|
|
if (err) {
|
|
// Error during responding, rethrow.
|
|
throw err;
|
|
}
|
|
}
|
|
async finalize() {
|
|
if (this.finalized) {
|
|
return;
|
|
}
|
|
// Consume unread body
|
|
const body = this.body;
|
|
const buf = new Uint8Array(1024);
|
|
while ((await body.read(buf)) !== null) {}
|
|
this.finalized = true;
|
|
}
|
|
};
|
|
exports_25("ServerRequest", ServerRequest);
|
|
Server = class Server {
|
|
constructor(listener) {
|
|
this.listener = listener;
|
|
this.closing = false;
|
|
this.connections = [];
|
|
}
|
|
close() {
|
|
this.closing = true;
|
|
this.listener.close();
|
|
for (const conn of this.connections) {
|
|
try {
|
|
conn.close();
|
|
} catch (e) {
|
|
// Connection might have been already closed
|
|
if (!(e instanceof Deno.errors.BadResource)) {
|
|
throw e;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// Yields all HTTP requests on a single TCP connection.
|
|
async *iterateHttpRequests(conn) {
|
|
const reader = new bufio_ts_2.BufReader(conn);
|
|
const writer = new bufio_ts_2.BufWriter(conn);
|
|
while (!this.closing) {
|
|
let request;
|
|
try {
|
|
request = await _io_ts_1.readRequest(conn, reader);
|
|
} catch (error) {
|
|
if (
|
|
error instanceof Deno.errors.InvalidData ||
|
|
error instanceof Deno.errors.UnexpectedEof
|
|
) {
|
|
// An error was thrown while parsing request headers.
|
|
await _io_ts_1.writeResponse(writer, {
|
|
status: 400,
|
|
body: utf8_ts_4.encode(`${error.message}\r\n\r\n`),
|
|
});
|
|
}
|
|
break;
|
|
}
|
|
if (request === null) {
|
|
break;
|
|
}
|
|
request.w = writer;
|
|
yield request;
|
|
// Wait for the request to be processed before we accept a new request on
|
|
// this connection.
|
|
const responseError = await request.done;
|
|
if (responseError) {
|
|
// Something bad happened during response.
|
|
// (likely other side closed during pipelined req)
|
|
// req.done implies this connection already closed, so we can just return.
|
|
this.untrackConnection(request.conn);
|
|
return;
|
|
}
|
|
// Consume unread body and trailers if receiver didn't consume those data
|
|
await request.finalize();
|
|
}
|
|
this.untrackConnection(conn);
|
|
try {
|
|
conn.close();
|
|
} catch (e) {
|
|
// might have been already closed
|
|
}
|
|
}
|
|
trackConnection(conn) {
|
|
this.connections.push(conn);
|
|
}
|
|
untrackConnection(conn) {
|
|
const index = this.connections.indexOf(conn);
|
|
if (index !== -1) {
|
|
this.connections.splice(index, 1);
|
|
}
|
|
}
|
|
// Accepts a new TCP connection and yields all HTTP requests that arrive on
|
|
// it. When a connection is accepted, it also creates a new iterator of the
|
|
// same kind and adds it to the request multiplexer so that another TCP
|
|
// connection can be accepted.
|
|
async *acceptConnAndIterateHttpRequests(mux) {
|
|
if (this.closing) {
|
|
return;
|
|
}
|
|
// Wait for a new connection.
|
|
let conn;
|
|
try {
|
|
conn = await this.listener.accept();
|
|
} catch (error) {
|
|
if (error instanceof Deno.errors.BadResource) {
|
|
return;
|
|
}
|
|
throw error;
|
|
}
|
|
this.trackConnection(conn);
|
|
// Try to accept another connection and add it to the multiplexer.
|
|
mux.add(this.acceptConnAndIterateHttpRequests(mux));
|
|
// Yield the requests that arrive on the just-accepted connection.
|
|
yield* this.iterateHttpRequests(conn);
|
|
}
|
|
[Symbol.asyncIterator]() {
|
|
const mux = new mod_ts_4.MuxAsyncIterator();
|
|
mux.add(this.acceptConnAndIterateHttpRequests(mux));
|
|
return mux.iterate();
|
|
}
|
|
};
|
|
exports_25("Server", Server);
|
|
},
|
|
};
|
|
},
|
|
);
|
|
System.register(
|
|
"file:///home/kou029w/deno-example/server",
|
|
["https://deno.land/std@0.56.0/http/server"],
|
|
function (exports_26, context_26) {
|
|
"use strict";
|
|
var server_ts_2;
|
|
var __moduleName = context_26 && context_26.id;
|
|
async function main() {
|
|
const port = 8000;
|
|
console.log(`http://localhost:${port}/`);
|
|
for await (const req of server_ts_2.serve({ port })) {
|
|
req.respond({ body: "Hello World\n" });
|
|
}
|
|
}
|
|
return {
|
|
setters: [
|
|
function (server_ts_2_1) {
|
|
server_ts_2 = server_ts_2_1;
|
|
},
|
|
],
|
|
execute: function () {
|
|
main();
|
|
},
|
|
};
|
|
},
|
|
);
|
|
|
|
__instantiate("file:///home/kou029w/deno-example/server");
|