@typed/fp
Version:
Data Structures and Resources for fp-ts
358 lines • 10.1 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createHistoryEnv = exports.parseHref = exports.writeFile = exports.write = exports.unlink = exports.symlink = exports.stat = exports.rmdir = exports.rm = exports.readdir = exports.readFile = exports.read = exports.mkdir = exports.link = exports.copyFile = exports.chmod = exports.HttpEnv = void 0;
const tslib_1 = require("tslib");
/**
* @typed/fp/node is a place to place implementations of environment from other modules that require or
* are best used with implementations specifically for node.js.
* @since 0.9.4
*/
const Ei = (0, tslib_1.__importStar)(require("fp-ts/Either"));
const fs = (0, tslib_1.__importStar)(require("fs"));
const node_fetch_1 = (0, tslib_1.__importDefault)(require("node-fetch"));
const D = (0, tslib_1.__importStar)(require("./Disposable"));
const E = (0, tslib_1.__importStar)(require("./Env"));
const EnvEither_1 = require("./EnvEither");
const R = (0, tslib_1.__importStar)(require("./Resume"));
/**
* @category Environment
* @since 0.9.4
*/
exports.HttpEnv = { http: E.fromResumeK(httpFetchRequest) };
function httpFetchRequest(uri, options = {}) {
return R.async((cb) => {
const { method = 'GET', headers = {}, body } = options;
const disposable = D.settable();
const abortController = new AbortController();
disposable.addDisposable({
dispose: () => abortController.abort(),
});
const init = {
method,
headers: Object.entries(headers).map(([key, value = '']) => [key, value]),
body: body !== null && body !== void 0 ? body : undefined,
credentials: 'include',
signal: abortController.signal,
};
async function makeRequest() {
const response = await (0, node_fetch_1.default)(uri, init);
const headers = {};
response.headers.forEach((value, key) => {
headers[key] = value;
});
const httpResponse = {
status: response.status,
body: await response.json().catch(() => response.text()),
headers,
};
if (!disposable.isDisposed()) {
disposable.addDisposable(cb(Ei.right(httpResponse)));
}
}
makeRequest().catch((error) => {
if (!disposable.isDisposed()) {
disposable.addDisposable(cb(Ei.left(error)));
}
});
return disposable;
});
}
/**
* @category FS
* @since 0.13.1
*/
exports.chmod = (0, EnvEither_1.fromPromiseK)(fs.promises.chmod);
/**
* @category FS
* @since 0.13.1
*/
exports.copyFile = (0, EnvEither_1.fromPromiseK)(fs.promises.copyFile);
/**
* @category FS
* @since 0.13.1
*/
exports.link = (0, EnvEither_1.fromPromiseK)(fs.promises.link);
/**
* @category FS
* @since 0.13.1
*/
exports.mkdir = (0, EnvEither_1.fromPromiseK)(fs.promises.mkdir);
/**
* @category FS
* @since 0.13.1
*/
exports.read = (0, EnvEither_1.fromPromiseK)(fs.promises.read);
/**
* @category FS
* @since 0.13.1
*/
exports.readFile = (0, EnvEither_1.fromPromiseK)(fs.promises.readFile);
/**
* @category FS
* @since 0.13.1
*/
exports.readdir = (0, EnvEither_1.fromPromiseK)(fs.promises.readdir);
/**
* @category FS
* @since 0.13.1
*/
exports.rm = (0, EnvEither_1.fromPromiseK)(fs.promises.rm);
/**
* @category FS
* @since 0.13.1
*/
exports.rmdir = (0, EnvEither_1.fromPromiseK)(fs.promises.rmdir);
/**
* @category FS
* @since 0.13.1
*/
exports.stat = (0, EnvEither_1.fromPromiseK)(fs.promises.stat);
/**
* @category FS
* @since 0.13.1
*/
exports.symlink = (0, EnvEither_1.fromPromiseK)(fs.promises.symlink);
/**
* @category FS
* @since 0.13.1
*/
exports.unlink = (0, EnvEither_1.fromPromiseK)(fs.promises.unlink);
/**
* @category FS
* @since 0.13.1
*/
exports.write = (0, EnvEither_1.fromPromiseK)(fs.promises.write);
/**
* @category FS
* @since 0.13.1
*/
exports.writeFile = (0, EnvEither_1.fromPromiseK)(fs.promises.writeFile);
/**
* An in-memory implementation of `History`.
* @category In-Memory Mock
* @since 0.13.2
* @internal
*/
class ServerHistory {
constructor(location) {
// Does not affect behavior
this.scrollRestoration = 'auto';
// tslint:disable-next-line:variable-name
this._index = 0;
this.location = location;
this._states = [{ state: null, url: this.location.pathname }];
}
set index(value) {
this._index = value;
const { url } = this._states[this._index];
this.location.replace(url);
}
get index() {
return this._index;
}
get length() {
return this._states.length;
}
get state() {
const { state } = this._states[this.index];
return state;
}
go(quanity = 0) {
if (quanity === 0) {
return void 0;
}
const minIndex = 0;
const maxIndex = this.length - 1;
this.index = Math.max(minIndex, Math.min(maxIndex, this.index + quanity));
}
back() {
this.go(-1);
}
forward() {
this.go(1);
}
pushState(state, _, url) {
this._states = this._states.slice(0, this.index).concat({ state, url });
this.index = this._states.length - 1;
}
replaceState(state, _, url) {
this._states[this.index] = { state, url };
}
}
const HTTPS_PROTOCOL = 'https:';
const HTTPS_DEFAULT_PORT = '443';
const HTTP_DEFAULT_PORT = '80';
/**
* An in-memory implementation of `Location`.
* @category In-Memory Mock
* @since 0.13.2
* @internal
*/
class ServerLocation {
constructor(url) {
this.updateHref(url);
}
get ancestorOrigins() {
return [];
}
get hash() {
return parseValue('hash', this);
}
set hash(value) {
const hash = value.startsWith('#') ? value : '#' + value;
replace('hash', hash, this);
}
get host() {
return parseValue('host', this);
}
set host(value) {
replace('host', value, this);
}
get hostname() {
return parseValue('hostname', this);
}
set hostname(value) {
replace('hostname', value, this);
}
get pathname() {
return parseValue('pathname', this);
}
set pathname(value) {
replace('pathname', value, this);
}
get port() {
const { href } = this;
const { port, protocol } = parseHref(href);
if (port) {
return port;
}
return protocol === HTTPS_PROTOCOL ? HTTPS_DEFAULT_PORT : HTTP_DEFAULT_PORT;
}
set port(value) {
replace('port', value, this);
}
get protocol() {
return parseValue('protocol', this) || 'http:';
}
set protocol(value) {
replace('protocol', value, this);
}
get search() {
return parseValue('search', this);
}
set search(value) {
const search = value.startsWith('?') ? value : '?' + value;
replace('search', search, this);
}
get origin() {
return this.protocol + '//' + this.host;
}
assign(url) {
this.updateHref(url);
if (this.history) {
this.history.pushState(null, '', this.href);
}
}
reload() {
// Does not have defined behavior outside of browser
}
replace(url) {
this.updateHref(url);
if (this.history) {
this.history.replaceState(null, '', this.href);
}
}
toString() {
return this.href;
}
// ServerLocation Specific
setHistory(history) {
this.history = history;
return this;
}
updateHref(url) {
const parsed = parseHref(url);
const { host, relative } = parsed;
let href = parsed.href;
if (this.host && !host) {
href = this.host + href;
}
const { protocol } = parseHref(href);
if (href !== relative && this.protocol && !protocol) {
href = this.protocol + '//' + href;
}
this.href = href;
}
}
function replace(key, value, location) {
const { href } = location;
const currentValue = parseHref(href)[key];
const updateHref = href.replace(currentValue, value);
location.replace(updateHref);
if (location.history) {
location.history.pushState(null, '', location.href);
}
}
function parseValue(key, location) {
return parseHref(location.href)[key];
}
const HREF_REGEX = /^(?:([^:/?#]+):)?(?:\/\/((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:/?#]*)(?::(\d*))?))?((((?:[^?#/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/;
/**
* Parses an href into JSON.
* @category Parser
* @since 0.13.2
* */
function parseHref(href) {
const matches = HREF_REGEX.exec(href);
const parsedHref = {};
for (let i = 0; i < keyCount; ++i) {
const key = keys[i];
let value = matches[i] || '';
if (key === 'search' && value) {
value = '?' + value;
}
if (key === 'protocol' && value && !value.endsWith(':')) {
value = value + ':';
}
if (key === 'hash') {
value = '#' + value;
}
parsedHref[key] = value;
}
return parsedHref;
}
exports.parseHref = parseHref;
const keys = [
'href',
'protocol',
'host',
'userInfo',
'username',
'password',
'hostname',
'port',
'relative',
'pathname',
'directory',
'file',
'search',
'hash',
];
const keyCount = keys.length;
/**
* Create A History Environment that works in browser and non-browser environments
* @param href :: initial href to use
* @category Environment
* @since 0.13.2
*/
function createHistoryEnv(href = '/') {
const serverLocation = new ServerLocation(href);
const serverHistory = new ServerHistory(serverLocation);
serverLocation.setHistory(serverHistory);
return {
location: serverLocation,
history: serverHistory,
};
}
exports.createHistoryEnv = createHistoryEnv;
//# sourceMappingURL=node.js.map