New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@kaciras/utilities

Package Overview
Dependencies
Maintainers
1
Versions
40
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@kaciras/utilities - npm Package Compare versions

Comparing version 0.5.1 to 0.6.0

200

dist/browser.js

@@ -267,2 +267,80 @@ const htmlEscapes = {

}
/**
* A simple string template engine, only support replace placeholders.
*
* It 10x faster than String.replaceAll() by splits the string ahead of time.
*
* @example
* const template = "<html>...</html>";
* const newComposite = compositor(template, {
* metadata: "<!--ssr-metadata-->",
* bodyAttrs: /(?<=<body.*?)(?=>)/s,
* appHtml: /(?<=<body.*?>).*(?=<\/body>)/s,
* });
*
* const c = newComposite();
* c.put("appHtml", appHtml);
* c.put("metadata", meta);
* c.put("bodyAttrs", ` class="${bodyClass}"`);
* return composite.toString();
*
* @param template The template string
* @param placeholders An object contains placeholders with its name as key.
*/ function compositor(template, placeholders) {
const nameToSlot = new Map();
const positions = [];
for (const name of Object.keys(placeholders)){
const pattern = placeholders[name];
let startPos;
let endPos;
if (typeof pattern === "string") {
startPos = template.indexOf(pattern);
if (startPos === -1) {
throw new Error("No match for: " + pattern);
}
endPos = startPos + pattern.length;
} else {
const match = pattern.exec(template);
if (!match) {
throw new Error("No match for: " + pattern);
}
startPos = match.index;
endPos = startPos + match[0].length;
}
positions.push({
name,
startPos,
endPos
});
}
// Sort by start position so we can check for overlap.
positions.sort((a, b)=>a.startPos - b.startPos);
let lastEnd = 0;
const parts = [];
for(let i = 0; i < positions.length; i++){
const { name: name1 , startPos: startPos1 , endPos: endPos1 } = positions[i];
nameToSlot.set(name1, i * 2 + 1);
if (startPos1 < lastEnd) {
throw new Error("Placeholder overlapped.");
}
parts.push(template.slice(lastEnd, startPos1));
parts.push(template.slice(startPos1, lastEnd = endPos1));
}
parts.push(template.slice(lastEnd));
return ()=>new Composite(nameToSlot, [
...parts
]);
}
class Composite {
constructor(nameToSlot, parts){
this.parts = parts;
this.nameToSlot = nameToSlot;
}
toString() {
return this.parts.join("");
}
put(name, value) {
this.parts[this.nameToSlot.get(name)] = value;
}
}

@@ -291,6 +369,118 @@ /**

}
class FetchClientError extends Error {
constructor(response){
super(`Fetch failed with status: ${response.status}`);
this.response = response;
this.code = response.status;
this.name = "FetchClientError";
}
}
const defaultRequest = {
credentials: "include"
};
async function check(response) {
if (response.ok) {
return response;
}
throw new FetchClientError(response);
}
/**
* Wrapper for Promise<Response>, provide status checking and useful method alias.
*
* @example
* // await it will check the response status.
* try {
* const response = await client.get(...);
* assert(response.ok);
* } catch (e) {
* console.error(e.message);
* }
*
* // Use `raw` to get the original response promise.
* const unchecked = await client.get(...).raw;
*
* // Get the response body in JSON format.
* const data = await client.get(...).json<Type>();
*
* // Get the Location header.
* const location = await apiService.get(...).location;
*/ class ResponseFacade {
constructor(raw){
this.raw = raw;
}
json() {
return this.then((r)=>r.json());
}
get location() {
return this.then((r)=>r.headers.get("location"));
}
get [Symbol.toStringTag]() {
return "ResponseFacade";
}
catch(onRejected) {
return this.raw.then(check).catch(onRejected);
}
finally(onFinally) {
return this.raw.then(check).finally(onFinally);
}
then(onFulfilled, onRejected) {
return this.raw.then(check).then(onFulfilled, onRejected);
}
}
/**
* A very simple helper to make `fetch` simpler.
*/ class FetchClient {
constructor(baseURL = "", init = defaultRequest){
this.init = init;
this.baseURL = baseURL;
}
fetch(url, method, data, params) {
const { baseURL , init } = this;
// https://github.com/whatwg/url/issues/427
if (params) {
const searchParams = new URLSearchParams();
for (const k of Object.keys(params)){
if (params[k] !== undefined) searchParams.set(k, params[k]);
}
url = `${url}?${searchParams}`;
}
const headers = new Headers(init.headers);
const custom = {
method,
headers
};
// fetch will auto set content-type if body is some types.
if (data instanceof FormData) {
custom.body = data;
} else if (data) {
custom.body = JSON.stringify(data);
headers.set("content-type", "application/json");
}
const request = new Request(new URL(url, baseURL), init);
return new ResponseFacade(fetch(request, custom));
}
head(url, params) {
return this.fetch(url, "HEAD", null, params);
}
get(url, params) {
return this.fetch(url, "GET", null, params);
}
delete(url, params) {
return this.fetch(url, "DELETE", null, params);
}
post(url, data, params) {
return this.fetch(url, "POST", data, params);
}
put(url, data, params) {
return this.fetch(url, "PUT", data, params);
}
patch(url, data, params) {
return this.fetch(url, "PATCH", data, params);
}
}
const NOOP = ()=>{};
const noop = ()=>{};
const identity = (v)=>v;
/**
* An AbortSignal object that never aborts.
* An AbortSignal that never aborts.
*/ const NeverAbort = {

@@ -342,3 +532,3 @@ aborted: false,

*/ function silencePromise(value) {
if (typeof value?.then === "function") value.catch(NOOP);
if (typeof value?.then === "function") value.catch(noop);
}

@@ -467,3 +657,3 @@ /**

isError: true
}, []);
});
}

@@ -668,2 +858,2 @@ }

export { AbortError, LRUCache, MultiEventEmitter, MultiMap, NOOP, NeverAbort, rpc as RPC, SingleEventEmitter, TimeUnit, base64url, blobToBase64URL, escapeHTML, fetchFile, formatDuration, formatSize, parseSize, saveFile, selectFile, sha256, silencePromise, sleep, svgToUrl, uniqueId };
export { AbortError, Composite, FetchClient, FetchClientError, LRUCache, MultiEventEmitter, MultiMap, NeverAbort, rpc as RPC, ResponseFacade, SingleEventEmitter, TimeUnit, base64url, blobToBase64URL, compositor, escapeHTML, fetchFile, formatDuration, formatSize, identity, noop, parseSize, saveFile, selectFile, sha256, silencePromise, sleep, svgToUrl, uniqueId };

@@ -157,2 +157,136 @@ import process from 'process';

/**
* Fetch the resource into a File object.
*
* @param request This defines the resource that you wish to fetch.
* @param init An object containing any custom settings that you want to apply to the request.
*/ async function fetchFile(request, init) {
const url = typeof request === "string" ? request : request.url;
const response = await fetch(request, init);
if (!response.ok) {
throw new Error(`Failed to fetch (${response.status}) ${url}`);
}
const blob = await response.blob();
const timeHeader = response.headers.get("last-modified");
const lastModified = timeHeader ? new Date(timeHeader).getTime() : undefined;
const name = new URL(url).pathname.split("/").at(-1) || "download";
return new File([
blob
], name, {
type: blob.type,
lastModified
});
}
class FetchClientError extends Error {
constructor(response){
super(`Fetch failed with status: ${response.status}`);
this.response = response;
this.code = response.status;
this.name = "FetchClientError";
}
}
const defaultRequest = {
credentials: "include"
};
async function check(response) {
if (response.ok) {
return response;
}
throw new FetchClientError(response);
}
/**
* Wrapper for Promise<Response>, provide status checking and useful method alias.
*
* @example
* // await it will check the response status.
* try {
* const response = await client.get(...);
* assert(response.ok);
* } catch (e) {
* console.error(e.message);
* }
*
* // Use `raw` to get the original response promise.
* const unchecked = await client.get(...).raw;
*
* // Get the response body in JSON format.
* const data = await client.get(...).json<Type>();
*
* // Get the Location header.
* const location = await apiService.get(...).location;
*/ class ResponseFacade {
constructor(raw){
this.raw = raw;
}
json() {
return this.then((r)=>r.json());
}
get location() {
return this.then((r)=>r.headers.get("location"));
}
get [Symbol.toStringTag]() {
return "ResponseFacade";
}
catch(onRejected) {
return this.raw.then(check).catch(onRejected);
}
finally(onFinally) {
return this.raw.then(check).finally(onFinally);
}
then(onFulfilled, onRejected) {
return this.raw.then(check).then(onFulfilled, onRejected);
}
}
/**
* A very simple helper to make `fetch` simpler.
*/ class FetchClient {
constructor(baseURL = "", init = defaultRequest){
this.init = init;
this.baseURL = baseURL;
}
fetch(url, method, data, params) {
const { baseURL , init } = this;
// https://github.com/whatwg/url/issues/427
if (params) {
const searchParams = new URLSearchParams();
for (const k of Object.keys(params)){
if (params[k] !== undefined) searchParams.set(k, params[k]);
}
url = `${url}?${searchParams}`;
}
const headers = new Headers(init.headers);
const custom = {
method,
headers
};
// fetch will auto set content-type if body is some types.
if (data instanceof FormData) {
custom.body = data;
} else if (data) {
custom.body = JSON.stringify(data);
headers.set("content-type", "application/json");
}
const request = new Request(new URL(url, baseURL), init);
return new ResponseFacade(fetch(request, custom));
}
head(url, params) {
return this.fetch(url, "HEAD", null, params);
}
get(url, params) {
return this.fetch(url, "GET", null, params);
}
delete(url, params) {
return this.fetch(url, "DELETE", null, params);
}
post(url, data, params) {
return this.fetch(url, "POST", data, params);
}
put(url, data, params) {
return this.fetch(url, "PUT", data, params);
}
patch(url, data, params) {
return this.fetch(url, "PATCH", data, params);
}
}
var TimeUnit;

@@ -273,6 +407,85 @@ (function(TimeUnit) {

}
/**
* A simple string template engine, only support replace placeholders.
*
* It 10x faster than String.replaceAll() by splits the string ahead of time.
*
* @example
* const template = "<html>...</html>";
* const newComposite = compositor(template, {
* metadata: "<!--ssr-metadata-->",
* bodyAttrs: /(?<=<body.*?)(?=>)/s,
* appHtml: /(?<=<body.*?>).*(?=<\/body>)/s,
* });
*
* const c = newComposite();
* c.put("appHtml", appHtml);
* c.put("metadata", meta);
* c.put("bodyAttrs", ` class="${bodyClass}"`);
* return composite.toString();
*
* @param template The template string
* @param placeholders An object contains placeholders with its name as key.
*/ function compositor(template, placeholders) {
const nameToSlot = new Map();
const positions = [];
for (const name of Object.keys(placeholders)){
const pattern = placeholders[name];
let startPos;
let endPos;
if (typeof pattern === "string") {
startPos = template.indexOf(pattern);
if (startPos === -1) {
throw new Error("No match for: " + pattern);
}
endPos = startPos + pattern.length;
} else {
const match = pattern.exec(template);
if (!match) {
throw new Error("No match for: " + pattern);
}
startPos = match.index;
endPos = startPos + match[0].length;
}
positions.push({
name,
startPos,
endPos
});
}
// Sort by start position so we can check for overlap.
positions.sort((a, b)=>a.startPos - b.startPos);
let lastEnd = 0;
const parts = [];
for(let i = 0; i < positions.length; i++){
const { name: name1 , startPos: startPos1 , endPos: endPos1 } = positions[i];
nameToSlot.set(name1, i * 2 + 1);
if (startPos1 < lastEnd) {
throw new Error("Placeholder overlapped.");
}
parts.push(template.slice(lastEnd, startPos1));
parts.push(template.slice(startPos1, lastEnd = endPos1));
}
parts.push(template.slice(lastEnd));
return ()=>new Composite(nameToSlot, [
...parts
]);
}
class Composite {
constructor(nameToSlot, parts){
this.parts = parts;
this.nameToSlot = nameToSlot;
}
toString() {
return this.parts.join("");
}
put(name, value) {
this.parts[this.nameToSlot.get(name)] = value;
}
}
const NOOP = ()=>{};
const noop = ()=>{};
const identity = (v)=>v;
/**
* An AbortSignal object that never aborts.
* An AbortSignal that never aborts.
*/ const NeverAbort = {

@@ -325,3 +538,3 @@ aborted: false,

*/ function silencePromise(value) {
if (typeof value?.then === "function") value.catch(NOOP);
if (typeof value?.then === "function") value.catch(noop);
}

@@ -410,3 +623,3 @@ /**

isError: true
}, []);
});
}

@@ -639,2 +852,2 @@ }

export { AbortError, LRUCache, MultiEventEmitter, MultiMap, NOOP, NeverAbort, rpc as RPC, SingleEventEmitter, TimeUnit, base64url, blobToBase64URL, escapeHTML, formatDuration, formatSize, onExit, parseSize, sha256, silencePromise, sleep, svgToUrl, uniqueId };
export { AbortError, Composite, FetchClient, FetchClientError, LRUCache, MultiEventEmitter, MultiMap, NeverAbort, rpc as RPC, ResponseFacade, SingleEventEmitter, TimeUnit, base64url, blobToBase64URL, compositor, escapeHTML, fetchFile, formatDuration, formatSize, identity, noop, onExit, parseSize, sha256, silencePromise, sleep, svgToUrl, uniqueId };

19

package.json
{
"name": "@kaciras/utilities",
"version": "0.5.1",
"version": "0.6.0",
"license": "MIT",

@@ -26,12 +26,13 @@ "description": "A set of common JS functions for node and browser.",

"@kaciras/eslint-config-typescript": "^2.5.0",
"@rollup/plugin-replace": "^5.0.1",
"@stryker-mutator/core": "^6.3.0",
"@stryker-mutator/jest-runner": "^6.3.0",
"@swc/core": "^1.3.21",
"@swc/jest": "^0.2.23",
"@types/node": "^18.11.11",
"eslint": "^8.29.0",
"@rollup/plugin-replace": "^5.0.2",
"@stryker-mutator/core": "^6.3.1",
"@stryker-mutator/jest-runner": "^6.3.1",
"@swc/core": "^1.3.24",
"@swc/jest": "^0.2.24",
"@types/node": "^18.11.18",
"eslint": "^8.30.0",
"is-builtin-module": "^3.2.0",
"jest": "^29.3.1",
"rollup": "^3.6.0",
"mockttp": "^3.6.2",
"rollup": "^3.8.1",
"typescript": "^4.9.4"

@@ -38,0 +39,0 @@ },

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc