0
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-10-31 09:14:20 -04:00
denoland-deno/ext/web/00_infra.js
Bartek Iwańczuk d47147fb6a
feat(ext/node): embed std/node into the snapshot (#17724)
This commit moves "deno_std/node" in "ext/node" crate. The code is
transpiled and snapshotted during the build process.

During the first pass a minimal amount of work was done to create the
snapshot, a lot of code in "ext/node" depends on presence of "Deno"
global. This code will be gradually fixed in the follow up PRs to migrate
it to import relevant APIs from "internal:" modules.

Currently the code from snapshot is not used in any way, and all
Node/npm compatibility still uses code from 
"https://deno.land/std/node" (or from the location specified by 
"DENO_NODE_COMPAT_URL"). This will also be handled in a follow 
up PRs.

---------

Co-authored-by: crowlkats <crowlkats@toaxl.com>
Co-authored-by: Divy Srivastava <dj.srivastava23@gmail.com>
Co-authored-by: Yoshiya Hinosawa <stibium121@gmail.com>
2023-02-14 17:38:45 +01:00

392 lines
9.1 KiB
JavaScript

// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
// @ts-check
/// <reference path="../../core/internal.d.ts" />
/// <reference path="../../core/lib.deno_core.d.ts" />
/// <reference path="../web/internal.d.ts" />
/// <reference path="../web/lib.deno_web.d.ts" />
const core = globalThis.Deno.core;
const ops = core.ops;
const primordials = globalThis.__bootstrap.primordials;
const {
ArrayPrototypeJoin,
ArrayPrototypeMap,
Error,
JSONStringify,
NumberPrototypeToString,
RegExp,
SafeArrayIterator,
String,
StringPrototypeCharAt,
StringPrototypeCharCodeAt,
StringPrototypeMatch,
StringPrototypePadStart,
StringPrototypeReplace,
StringPrototypeSlice,
StringPrototypeSubstring,
StringPrototypeToLowerCase,
StringPrototypeToUpperCase,
TypeError,
} = primordials;
const ASCII_DIGIT = ["\u0030-\u0039"];
const ASCII_UPPER_ALPHA = ["\u0041-\u005A"];
const ASCII_LOWER_ALPHA = ["\u0061-\u007A"];
const ASCII_ALPHA = [
...new SafeArrayIterator(ASCII_UPPER_ALPHA),
...new SafeArrayIterator(ASCII_LOWER_ALPHA),
];
const ASCII_ALPHANUMERIC = [
...new SafeArrayIterator(ASCII_DIGIT),
...new SafeArrayIterator(ASCII_ALPHA),
];
const HTTP_TAB_OR_SPACE = ["\u0009", "\u0020"];
const HTTP_WHITESPACE = [
"\u000A",
"\u000D",
...new SafeArrayIterator(HTTP_TAB_OR_SPACE),
];
const HTTP_TOKEN_CODE_POINT = [
"\u0021",
"\u0023",
"\u0024",
"\u0025",
"\u0026",
"\u0027",
"\u002A",
"\u002B",
"\u002D",
"\u002E",
"\u005E",
"\u005F",
"\u0060",
"\u007C",
"\u007E",
...new SafeArrayIterator(ASCII_ALPHANUMERIC),
];
const HTTP_TOKEN_CODE_POINT_RE = new RegExp(
`^[${regexMatcher(HTTP_TOKEN_CODE_POINT)}]+$`,
);
const HTTP_QUOTED_STRING_TOKEN_POINT = [
"\u0009",
"\u0020-\u007E",
"\u0080-\u00FF",
];
const HTTP_QUOTED_STRING_TOKEN_POINT_RE = new RegExp(
`^[${regexMatcher(HTTP_QUOTED_STRING_TOKEN_POINT)}]+$`,
);
const HTTP_TAB_OR_SPACE_MATCHER = regexMatcher(HTTP_TAB_OR_SPACE);
const HTTP_TAB_OR_SPACE_PREFIX_RE = new RegExp(
`^[${HTTP_TAB_OR_SPACE_MATCHER}]+`,
"g",
);
const HTTP_TAB_OR_SPACE_SUFFIX_RE = new RegExp(
`[${HTTP_TAB_OR_SPACE_MATCHER}]+$`,
"g",
);
const HTTP_WHITESPACE_MATCHER = regexMatcher(HTTP_WHITESPACE);
const HTTP_BETWEEN_WHITESPACE = new RegExp(
`^[${HTTP_WHITESPACE_MATCHER}]*(.*?)[${HTTP_WHITESPACE_MATCHER}]*$`,
);
const HTTP_WHITESPACE_PREFIX_RE = new RegExp(
`^[${HTTP_WHITESPACE_MATCHER}]+`,
"g",
);
const HTTP_WHITESPACE_SUFFIX_RE = new RegExp(
`[${HTTP_WHITESPACE_MATCHER}]+$`,
"g",
);
/**
* Turn a string of chars into a regex safe matcher.
* @param {string[]} chars
* @returns {string}
*/
function regexMatcher(chars) {
const matchers = ArrayPrototypeMap(chars, (char) => {
if (char.length === 1) {
const a = StringPrototypePadStart(
NumberPrototypeToString(StringPrototypeCharCodeAt(char, 0), 16),
4,
"0",
);
return `\\u${a}`;
} else if (char.length === 3 && char[1] === "-") {
const a = StringPrototypePadStart(
NumberPrototypeToString(StringPrototypeCharCodeAt(char, 0), 16),
4,
"0",
);
const b = StringPrototypePadStart(
NumberPrototypeToString(StringPrototypeCharCodeAt(char, 2), 16),
4,
"0",
);
return `\\u${a}-\\u${b}`;
} else {
throw TypeError("unreachable");
}
});
return ArrayPrototypeJoin(matchers, "");
}
/**
* https://infra.spec.whatwg.org/#collect-a-sequence-of-code-points
* @param {string} input
* @param {number} position
* @param {(char: string) => boolean} condition
* @returns {{result: string, position: number}}
*/
function collectSequenceOfCodepoints(input, position, condition) {
const start = position;
for (
let c = StringPrototypeCharAt(input, position);
position < input.length && condition(c);
c = StringPrototypeCharAt(input, ++position)
);
return { result: StringPrototypeSlice(input, start, position), position };
}
/**
* @param {string} s
* @returns {string}
*/
function byteUpperCase(s) {
return StringPrototypeReplace(
String(s),
/[a-z]/g,
function byteUpperCaseReplace(c) {
return StringPrototypeToUpperCase(c);
},
);
}
/**
* @param {string} s
* @returns {string}
*/
function byteLowerCase(s) {
// NOTE: correct since all callers convert to ByteString first
// TODO(@AaronO): maybe prefer a ByteString_Lower webidl converter
return StringPrototypeToLowerCase(s);
}
/**
* https://fetch.spec.whatwg.org/#collect-an-http-quoted-string
* @param {string} input
* @param {number} position
* @param {boolean} extractValue
* @returns {{result: string, position: number}}
*/
function collectHttpQuotedString(input, position, extractValue) {
// 1.
const positionStart = position;
// 2.
let value = "";
// 3.
if (input[position] !== "\u0022") throw new TypeError('must be "');
// 4.
position++;
// 5.
while (true) {
// 5.1.
const res = collectSequenceOfCodepoints(
input,
position,
(c) => c !== "\u0022" && c !== "\u005C",
);
value += res.result;
position = res.position;
// 5.2.
if (position >= input.length) break;
// 5.3.
const quoteOrBackslash = input[position];
// 5.4.
position++;
// 5.5.
if (quoteOrBackslash === "\u005C") {
// 5.5.1.
if (position >= input.length) {
value += "\u005C";
break;
}
// 5.5.2.
value += input[position];
// 5.5.3.
position++;
} else { // 5.6.
// 5.6.1
if (quoteOrBackslash !== "\u0022") throw new TypeError('must be "');
// 5.6.2
break;
}
}
// 6.
if (extractValue) return { result: value, position };
// 7.
return {
result: StringPrototypeSubstring(input, positionStart, position + 1),
position,
};
}
/**
* @param {Uint8Array} data
* @returns {string}
*/
function forgivingBase64Encode(data) {
return ops.op_base64_encode(data);
}
/**
* @param {string} data
* @returns {Uint8Array}
*/
function forgivingBase64Decode(data) {
return ops.op_base64_decode(data);
}
// Taken from std/encoding/base64url.ts
/*
* Some variants allow or require omitting the padding '=' signs:
* https://en.wikipedia.org/wiki/Base64#The_URL_applications
* @param base64url
*/
/**
* @param {string} base64url
* @returns {string}
*/
function addPaddingToBase64url(base64url) {
if (base64url.length % 4 === 2) return base64url + "==";
if (base64url.length % 4 === 3) return base64url + "=";
if (base64url.length % 4 === 1) {
throw new TypeError("Illegal base64url string!");
}
return base64url;
}
/**
* @param {string} base64url
* @returns {string}
*/
function convertBase64urlToBase64(base64url) {
if (!/^[-_A-Z0-9]*?={0,2}$/i.test(base64url)) {
// Contains characters not part of base64url spec.
throw new TypeError("Failed to decode base64url: invalid character");
}
return addPaddingToBase64url(base64url).replace(/\-/g, "+").replace(
/_/g,
"/",
);
}
/**
* Encodes a given ArrayBuffer or string into a base64url representation
* @param {ArrayBuffer | string} data
* @returns {string}
*/
function forgivingBase64UrlEncode(data) {
return forgivingBase64Encode(
typeof data === "string" ? new TextEncoder().encode(data) : data,
).replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
}
/**
* Converts given base64url encoded data back to original
* @param {string} b64url
* @returns {Uint8Array}
*/
function forgivingBase64UrlDecode(b64url) {
return forgivingBase64Decode(convertBase64urlToBase64(b64url));
}
/**
* @param {string} char
* @returns {boolean}
*/
function isHttpWhitespace(char) {
switch (char) {
case "\u0009":
case "\u000A":
case "\u000D":
case "\u0020":
return true;
default:
return false;
}
}
/**
* @param {string} s
* @returns {string}
*/
function httpTrim(s) {
if (!isHttpWhitespace(s[0]) && !isHttpWhitespace(s[s.length - 1])) {
return s;
}
return StringPrototypeMatch(s, HTTP_BETWEEN_WHITESPACE)?.[1] ?? "";
}
class AssertionError extends Error {
constructor(msg) {
super(msg);
this.name = "AssertionError";
}
}
/**
* @param {unknown} cond
* @param {string=} msg
* @returns {asserts cond}
*/
function assert(cond, msg = "Assertion failed.") {
if (!cond) {
throw new AssertionError(msg);
}
}
/**
* @param {unknown} value
* @returns {string}
*/
function serializeJSValueToJSONString(value) {
const result = JSONStringify(value);
if (result === undefined) {
throw new TypeError("Value is not JSON serializable.");
}
return result;
}
export {
ASCII_ALPHA,
ASCII_ALPHANUMERIC,
ASCII_DIGIT,
ASCII_LOWER_ALPHA,
ASCII_UPPER_ALPHA,
assert,
AssertionError,
byteLowerCase,
byteUpperCase,
collectHttpQuotedString,
collectSequenceOfCodepoints,
forgivingBase64Decode,
forgivingBase64Encode,
forgivingBase64UrlDecode,
forgivingBase64UrlEncode,
HTTP_QUOTED_STRING_TOKEN_POINT,
HTTP_QUOTED_STRING_TOKEN_POINT_RE,
HTTP_TAB_OR_SPACE,
HTTP_TAB_OR_SPACE_PREFIX_RE,
HTTP_TAB_OR_SPACE_SUFFIX_RE,
HTTP_TOKEN_CODE_POINT,
HTTP_TOKEN_CODE_POINT_RE,
HTTP_WHITESPACE,
HTTP_WHITESPACE_PREFIX_RE,
HTTP_WHITESPACE_SUFFIX_RE,
httpTrim,
regexMatcher,
serializeJSValueToJSONString,
};