Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@percy/sdk-utils

Package Overview
Dependencies
Maintainers
6
Versions
222
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@percy/sdk-utils - npm Package Compare versions

Comparing version 1.1.0 to 1.1.1

dist/logger.js

568

dist/bundle.js

@@ -9,426 +9,2 @@ (function() {

const {
assign,
entries
} = Object; // matches ansi escape sequences
const ANSI_REG = new RegExp('[\\u001B\\u009B][[\\]()#;?]*((?:(?:[a-zA-Z\\d]*(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)' + '|(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))', 'g'); // color names by ansi escape code
const ANSI_COLORS = {
'91m': 'red',
'32m': 'green',
'93m': 'yellow',
'34m': 'blue',
'95m': 'magenta',
'90m': 'grey'
}; // colorize each line of a string using an ansi escape sequence
const LINE_REG = /^.*$/gm;
function colorize(code, str) {
return str.replace(LINE_REG, line => `\u001b[${code}${line}\u001b[39m`);
} // map ansi colors to bound colorize functions
const colors = entries(ANSI_COLORS).reduce((colors, _ref) => {
let [code, name] = _ref;
return assign(colors, {
[name]: colorize.bind(null, code)
});
}, {});
function _defineProperty(obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true
});
} else {
obj[key] = value;
}
return obj;
}
const URL_REGEXP = /\bhttps?:\/\/[^\s/$.?#].[^\s]*\b/i;
const LOG_LEVELS = {
debug: 0,
info: 1,
warn: 2,
error: 3
}; // A PercyLogger instance retains logs in-memory for quick lookups while also writing log
// messages to stdout and stderr depending on the log level and debug string.
class PercyLogger {
// default log level
// namespace regular expressions used to determine which debug logs to write
// in-memory store for logs and meta info
// track deprecations to limit noisy logging
// static vars can be overriden for testing
// Handles setting env var values and returns a singleton
constructor() {
_defineProperty(this, "level", 'info');
_defineProperty(this, "namespaces", {
include: [/^.*?$/],
exclude: []
});
_defineProperty(this, "messages", new Set());
_defineProperty(this, "deprecations", new Set());
let {
instance = this
} = this.constructor;
if (process.env.PERCY_DEBUG) {
instance.debug(process.env.PERCY_DEBUG);
} else if (process.env.PERCY_LOGLEVEL) {
instance.loglevel(process.env.PERCY_LOGLEVEL);
}
this.constructor.instance = instance;
return instance;
} // Change log level at any time or return the current log level
loglevel(level) {
if (level) this.level = level;
return this.level;
} // Change namespaces by generating an array of namespace regular expressions from a
// comma separated debug string
debug(namespaces) {
if (this.namespaces.string === namespaces) return;
this.namespaces.string = namespaces;
namespaces = namespaces.split(/[\s,]+/).filter(Boolean);
if (!namespaces.length) return this.namespaces;
this.loglevel('debug');
this.namespaces = namespaces.reduce((namespaces, ns) => {
ns = ns.replace(/:?\*/g, m => m[0] === ':' ? ':?.*?' : '.*?');
if (ns[0] === '-') {
namespaces.exclude.push(new RegExp('^' + ns.substr(1) + '$'));
} else {
namespaces.include.push(new RegExp('^' + ns + '$'));
}
return namespaces;
}, {
string: namespaces,
include: [],
exclude: []
});
} // Creates a new log group and returns level specific functions for logging
group(name) {
return Object.keys(LOG_LEVELS).reduce((group, level) => Object.assign(group, {
[level]: this.log.bind(this, name, level)
}), {
deprecated: this.deprecated.bind(this, name),
shouldLog: this.shouldLog.bind(this, name),
progress: this.progress.bind(this, name),
format: this.format.bind(this, name),
loglevel: this.loglevel.bind(this),
stdout: this.constructor.stdout,
stderr: this.constructor.stderr
});
} // Query for a set of logs by filtering the in-memory store
query(filter) {
return Array.from(this.messages).filter(filter);
} // Formats messages before they are logged to stdio
format(debug, level, message, elapsed) {
let label = 'percy';
let suffix = '';
if (arguments.length === 1) {
// format(message)
[debug, message] = [null, debug];
} else if (arguments.length === 2) {
// format(debug, message)
[level, message] = [null, level];
}
if (this.level === 'debug') {
// include debug info in the label
if (debug) label += `:${debug}`; // include elapsed time since last log
if (elapsed != null) {
suffix = ' ' + colors.grey(`(${elapsed}ms)`);
}
}
label = colors.magenta(label);
if (level === 'error') {
// red errors
message = colors.red(message);
} else if (level === 'warn') {
// yellow warnings
message = colors.yellow(message);
} else if (level === 'info' || level === 'debug') {
// blue info and debug URLs
message = message.replace(URL_REGEXP, colors.blue('$&'));
}
return `[${label}] ${message}${suffix}`;
} // Replaces the current line with a log message
progress(debug, message, persist) {
if (!this.shouldLog(debug, 'info')) return;
let {
stdout
} = this.constructor;
if (stdout.isTTY || !this._progress) {
message && (message = this.format(debug, message));
if (stdout.isTTY) stdout.cursorTo(0);else message && (message = message + '\n');
if (message) stdout.write(message);
if (stdout.isTTY) stdout.clearLine(1);
}
this._progress = !!message && {
message,
persist
};
} // Returns true or false if the level and debug group can write messages to stdio
shouldLog(debug, level) {
return LOG_LEVELS[level] != null && LOG_LEVELS[level] >= LOG_LEVELS[this.level] && !this.namespaces.exclude.some(ns => ns.test(debug)) && this.namespaces.include.some(ns => ns.test(debug));
} // Ensures that deprecation messages are not logged more than once
deprecated(debug, message, meta) {
if (this.deprecations.has(message)) return;
this.deprecations.add(message);
this.log(debug, 'warn', `Warning: ${message}`, meta);
} // Returns true if a socket is present and ready
get isRemote() {
var _this$socket;
return ((_this$socket = this.socket) === null || _this$socket === void 0 ? void 0 : _this$socket.readyState) === 1;
} // Generic log method accepts a debug group, log level, log message, and optional meta
// information to store with the message and other info
log(debug, level, message) {
let meta = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
// message might be an error object
let isError = typeof message !== 'string' && (level === 'error' || level === 'debug');
let error = isError && message; // if remote, send logs there
if (this.isRemote) {
// serialize error messages
message = isError && 'stack' in error ? {
message: error.message,
stack: error.stack
} : message;
return this.socket.send(JSON.stringify({
log: [debug, level, message, {
remote: true,
...meta
}]
}));
} // ensure the message is a string
message = isError && message.stack || message.message || message.toString(); // timestamp each log
let timestamp = Date.now();
let entry = {
debug,
level,
message,
meta,
timestamp
};
this.messages.add(entry); // maybe write the message to stdio
if (this.shouldLog(debug, level)) {
let elapsed = timestamp - (this.lastlog || timestamp);
if (isError && this.level !== 'debug') message = error.toString();
this.write(level, this.format(debug, error ? 'error' : level, message, elapsed));
this.lastlog = timestamp;
}
} // Writes a message to stdio based on the loglevel
write(level, message) {
var _this$_progress;
let {
stdout,
stderr
} = this.constructor;
let progress = stdout.isTTY && this._progress;
if (progress) {
stdout.cursorTo(0);
stdout.clearLine();
}
(level === 'info' ? stdout : stderr).write(message + '\n');
if (!((_this$_progress = this._progress) !== null && _this$_progress !== void 0 && _this$_progress.persist)) delete this._progress;else if (progress) stdout.write(progress.message);
} // Opens a socket logging connection
connect(socket) {
// send logging environment info
let PERCY_DEBUG = process.env.PERCY_DEBUG;
let PERCY_LOGLEVEL = process.env.PERCY_LOGLEVEL || this.loglevel();
socket.send(JSON.stringify({
env: {
PERCY_DEBUG,
PERCY_LOGLEVEL
}
})); // attach remote logging handler
socket.onmessage = _ref => {
let {
data
} = _ref;
let {
log,
logAll
} = JSON.parse(data);
if (logAll) logAll.forEach(e => this.messages.add(e));
if (log) this.log(...log);
}; // return a cleanup function
return () => {
socket.onmessage = null;
};
} // Connects to a remote logger
async remote(createSocket) {
let timeout = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1000;
if (this.isRemote) return; // if not already connected, wait until the timeout
let err = await new Promise(resolve => {
let done = event => {
if (timeoutid == null) return;
timeoutid = clearTimeout(timeoutid);
if (this.socket) this.socket.onopen = this.socket.onerror = null;
resolve((event === null || event === void 0 ? void 0 : event.error) || (event === null || event === void 0 ? void 0 : event.type) === 'error' && 'Error: Socket connection failed');
};
let timeoutid = setTimeout(done, timeout, {
error: 'Error: Socket connection timed out'
});
Promise.resolve().then(async () => {
this.socket = await createSocket();
if (this.isRemote) return done();
this.socket.onopen = this.socket.onerror = done;
}).catch(error => done({
error
}));
}); // there was an error connecting, will fallback to normal logging
if (err) {
this.log('logger', 'debug', 'Unable to connect to remote logger');
this.log('logger', 'debug', err);
return;
} // send any messages already logged in this environment
if (this.messages.size) {
this.socket.send(JSON.stringify({
logAll: Array.from(this.messages).map(entry => ({ ...entry,
meta: {
remote: true,
...entry.meta
}
}))
}));
} // attach an incoming message handler
this.socket.onmessage = _ref2 => {
let {
data
} = _ref2;
let {
env
} = JSON.parse(data); // update local environment info
if (env) Object.assign(process.env, env);
}; // return a cleanup function
return () => {
this.socket.onmessage = null;
this.socket = null;
};
}
}
_defineProperty(PercyLogger, "stdout", process.stdout);
_defineProperty(PercyLogger, "stderr", process.stderr);
class PercyBrowserLogger extends PercyLogger {
write(level, message) {
let out = ['warn', 'error'].includes(level) ? level : 'log';
let colors = [];
message = message.replace(ANSI_REG, (_, ansi) => {
colors.push(`color:${ANSI_COLORS[ansi] || 'inherit'}`);
return '%c';
});
console[out](message, ...colors);
}
progress() {
console.error('The log.progress() method is not supported in browsers');
}
}
function logger(name) {
return new PercyBrowserLogger().group(name);
}
Object.assign(logger, {
format: function () {
return new PercyBrowserLogger().format(...arguments);
},
query: function () {
return new PercyBrowserLogger().query(...arguments);
},
connect: function () {
return new PercyBrowserLogger().connect(...arguments);
},
remote: function () {
return new PercyBrowserLogger().remote(...arguments);
},
loglevel: function () {
return new PercyBrowserLogger().loglevel(...arguments);
}
});
Object.defineProperties(logger, {
Logger: {
get: () => PercyBrowserLogger
},
stdout: {
get: () => PercyBrowserLogger.stdout
},
stderr: {
get: () => PercyBrowserLogger.stderr
}
});
// helper to create a version object from a string

@@ -493,2 +69,123 @@ function toVersion(str) {

const LOG_LEVELS = {
debug: 0,
info: 1,
warn: 2,
error: 3
}; // Create a small logger util using the specified namespace
function logger(namespace) {
return Object.keys(LOG_LEVELS).reduce((ns, lvl) => Object.assign(ns, {
[lvl]: log.bind(null, namespace, lvl)
}), {});
} // Set and/or return the local loglevel
const loglevel = logger.loglevel = lvl => {
return loglevel.lvl = lvl || loglevel.lvl || process.env.PERCY_LOGLEVEL || 'info';
}; // Track and send/write logs for the specified namespace and log level
const log = logger.log = (ns, lvl, msg, meta) => {
let err = typeof msg !== 'string' && (lvl === 'error' || lvl === 'debug');
meta = {
remote: true,
...meta
};
if (remote.socket) {
// prefer remote logging when available and serialize any errors
if (err) msg = {
name: msg.name,
message: msg.message,
stack: msg.stack
};
return remote.socket.send(JSON.stringify({
log: [ns, lvl, msg, meta]
}));
} else {
// keep log history when not remote
let [debug, level, message, timestamp] = [ns, lvl, msg, Date.now()];
(log.history || (log.history = [])).push({
debug,
level,
message,
meta,
timestamp
});
} // check if the specific level is within the local loglevel range
if (LOG_LEVELS[lvl] != null && LOG_LEVELS[lvl] >= LOG_LEVELS[loglevel()]) {
var _msg;
let debug = loglevel() === 'debug';
let label = debug ? `percy:${ns}` : 'percy'; // colorize the label when possible for consistency with the CLI logger
if (!process.env.__PERCY_BROWSERIFIED__) label = `\u001b[95m${label}\u001b[39m`;
msg = `[${label}] ${err && debug && ((_msg = msg) === null || _msg === void 0 ? void 0 : _msg.stack) || msg}`;
if (process.env.__PERCY_BROWSERIFIED__) {
// use console[warn|error|log] in browsers
console[['warn', 'error'].includes(lvl) ? lvl : 'log'](msg);
} else {
// use process[stdout|stderr].write in node
process[lvl === 'info' ? 'stdout' : 'stderr'].write(msg + '\n');
}
}
}; // Create a new WebSocket and resolve with it once connected
async function createWebSocket(address) {
let timeout = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1000;
// attempt to import `ws` in node environments
let WebSocket = process.env.__PERCY_BROWSERIFIED__
/* eslint-disable-next-line import/no-extraneous-dependencies */
? window.WebSocket : (await ({})).default;
let ws = new WebSocket(address.replace(/^http/, 'ws'));
return new Promise((resolve, reject) => {
let done = ws.onopen = ws.onerror = e => {
var _ws$_socket;
(_ws$_socket = ws._socket) === null || _ws$_socket === void 0 ? void 0 : _ws$_socket.unref();
clearTimeout(timeoutid);
ws.onopen = ws.onerror = null;
if (!e.error && e.type !== 'error') return resolve(ws);else reject(e.error || 'Error: Socket connection failed');
};
let timeoutid = setTimeout(done, timeout, {
error: 'Error: Socket connection timed out'
});
});
} // Connect to a remote logger at the specified address within the timeout
const remote = logger.remote = async timeout => {
try {
var _remote$socket;
// already connected
if (((_remote$socket = remote.socket) === null || _remote$socket === void 0 ? void 0 : _remote$socket.readyState) === 1) return; // connect to namespaced logging address
let address = new URL('/logger', info.address).href; // create and cache a websocket connection
let ws = remote.socket = await createWebSocket(address, timeout); // accept loglevel updates
/* istanbul ignore next: difficult to test currently */
ws.onmessage = e => loglevel(JSON.parse(e.data).loglevel); // cleanup message handler on close
ws.onclose = () => remote.socket = ws.onmessage = ws.onclose = null; // send any messages already logged in this environment
if (log.history) ws.send(JSON.stringify({
messages: log.history
}));
} catch (err) {
// there was an error connecting, will fallback to minimal logging
log('utils', 'debug', 'Unable to connect to remote logger');
log('utils', 'debug', err);
}
};
async function request(path) {

@@ -541,3 +238,3 @@ let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};

default: http
} = await import('http');
} = await ({});
return new Promise((resolve, reject) => {

@@ -558,21 +255,2 @@ http.request(url, options).on('response', response => {

async function connectRemoteLogger() {
await logger.remote(async () => {
let url = info.address.replace('http', 'ws');
if (process.env.__PERCY_BROWSERIFIED__) {
return new window.WebSocket(url);
} else {
/* eslint-disable-next-line import/no-extraneous-dependencies */
let {
default: WebSocket
} = await import('ws');
let ws = new WebSocket(url); // allow node to exit with an active connection
return ws.once('open', () => ws._socket.unref());
}
});
} // Check if Percy is enabled using the healthcheck endpoint
async function isPercyEnabled() {

@@ -603,3 +281,3 @@ if (info.enabled == null) {

if (info.enabled) {
await connectRemoteLogger();
await logger.remote();
}

@@ -606,0 +284,0 @@ }

@@ -1,10 +0,72 @@

import logger from '@percy/logger';
import percy from './percy-info.js';
import request from './request.js';
import isPercyEnabled from './percy-enabled.js';
import waitForPercyIdle from './percy-idle.js';
import fetchPercyDOM from './percy-dom.js';
import postSnapshot from './post-snapshot.js';
export { logger, percy, request, isPercyEnabled, waitForPercyIdle, fetchPercyDOM, postSnapshot }; // export the namespace by default
"use strict";
export * as default from './index.js';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
Object.defineProperty(exports, "fetchPercyDOM", {
enumerable: true,
get: function () {
return _percyDom.default;
}
});
Object.defineProperty(exports, "isPercyEnabled", {
enumerable: true,
get: function () {
return _percyEnabled.default;
}
});
Object.defineProperty(exports, "logger", {
enumerable: true,
get: function () {
return _logger.default;
}
});
Object.defineProperty(exports, "percy", {
enumerable: true,
get: function () {
return _percyInfo.default;
}
});
Object.defineProperty(exports, "postSnapshot", {
enumerable: true,
get: function () {
return _postSnapshot.default;
}
});
Object.defineProperty(exports, "request", {
enumerable: true,
get: function () {
return _request.default;
}
});
Object.defineProperty(exports, "waitForPercyIdle", {
enumerable: true,
get: function () {
return _percyIdle.default;
}
});
var _logger = _interopRequireDefault(require("./logger.js"));
var _percyInfo = _interopRequireDefault(require("./percy-info.js"));
var _request = _interopRequireDefault(require("./request.js"));
var _percyEnabled = _interopRequireDefault(require("./percy-enabled.js"));
var _percyIdle = _interopRequireDefault(require("./percy-idle.js"));
var _percyDom = _interopRequireDefault(require("./percy-dom.js"));
var _postSnapshot = _interopRequireDefault(require("./post-snapshot.js"));
var _default = _interopRequireWildcard(require("./index.js"));
exports.default = _default;
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

@@ -1,12 +0,26 @@

import percy from './percy-info.js';
import request from './request.js'; // Fetch and cache the @percy/dom script
"use strict";
export async function fetchPercyDOM() {
if (percy.domScript == null) {
let response = await request('/percy/dom.js');
percy.domScript = response.body;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
exports.fetchPercyDOM = fetchPercyDOM;
var _percyInfo = _interopRequireDefault(require("./percy-info.js"));
var _request = _interopRequireDefault(require("./request.js"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
// Fetch and cache the @percy/dom script
async function fetchPercyDOM() {
if (_percyInfo.default.domScript == null) {
let response = await (0, _request.default)('/percy/dom.js');
_percyInfo.default.domScript = response.body;
}
return percy.domScript;
return _percyInfo.default.domScript;
}
export default fetchPercyDOM;
var _default = fetchPercyDOM;
exports.default = _default;

@@ -1,44 +0,38 @@

import logger from '@percy/logger';
import percy from './percy-info.js';
import request from './request.js'; // Create a socket to connect to a remote logger
"use strict";
async function connectRemoteLogger() {
await logger.remote(async () => {
let url = percy.address.replace('http', 'ws');
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
exports.isPercyEnabled = isPercyEnabled;
if (process.env.__PERCY_BROWSERIFIED__) {
return new window.WebSocket(url);
} else {
/* eslint-disable-next-line import/no-extraneous-dependencies */
let {
default: WebSocket
} = await import('ws');
let ws = new WebSocket(url); // allow node to exit with an active connection
var _percyInfo = _interopRequireDefault(require("./percy-info.js"));
return ws.once('open', () => ws._socket.unref());
}
});
} // Check if Percy is enabled using the healthcheck endpoint
var _request = _interopRequireDefault(require("./request.js"));
var _logger = _interopRequireDefault(require("./logger.js"));
export async function isPercyEnabled() {
if (percy.enabled == null) {
let log = logger('utils');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
// Check if Percy is enabled using the healthcheck endpoint
async function isPercyEnabled() {
if (_percyInfo.default.enabled == null) {
let log = (0, _logger.default)('utils');
let error;
try {
let response = await request('/percy/healthcheck');
percy.version = response.headers['x-percy-core-version'];
percy.config = response.body.config;
percy.enabled = true;
let response = await (0, _request.default)('/percy/healthcheck');
_percyInfo.default.version = response.headers['x-percy-core-version'];
_percyInfo.default.config = response.body.config;
_percyInfo.default.enabled = true;
} catch (e) {
percy.enabled = false;
_percyInfo.default.enabled = false;
error = e;
}
if (percy.enabled && percy.version.major !== 1) {
if (_percyInfo.default.enabled && _percyInfo.default.version.major !== 1) {
log.info('Unsupported Percy CLI version, disabling snapshots');
log.debug(`Found version: ${percy.version}`);
percy.enabled = false;
} else if (!percy.enabled) {
log.debug(`Found version: ${_percyInfo.default.version}`);
_percyInfo.default.enabled = false;
} else if (!_percyInfo.default.enabled) {
log.info('Percy is not running, disabling snapshots');

@@ -48,9 +42,11 @@ log.debug(error);

if (percy.enabled) {
await connectRemoteLogger();
if (_percyInfo.default.enabled) {
await _logger.default.remote();
}
}
return percy.enabled;
return _percyInfo.default.enabled;
}
export default isPercyEnabled;
var _default = isPercyEnabled;
exports.default = _default;

@@ -1,6 +0,18 @@

import request from './request.js';
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
exports.waitForPercyIdle = waitForPercyIdle;
var _request = _interopRequireDefault(require("./request.js"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
const RETRY_ERROR_CODES = ['ECONNRESET', 'ETIMEDOUT'];
export async function waitForPercyIdle() {
async function waitForPercyIdle() {
try {
return !!(await request('/percy/idle'));
return !!(await (0, _request.default)('/percy/idle'));
} catch (e) {

@@ -10,2 +22,4 @@ return RETRY_ERROR_CODES.includes(e.code) && waitForPercyIdle();

}
export default waitForPercyIdle;
var _default = waitForPercyIdle;
exports.default = _default;

@@ -0,1 +1,8 @@

"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
// helper to create a version object from a string

@@ -59,2 +66,3 @@ function toVersion(str) {

};
export default info;
var _default = info;
exports.default = _default;

@@ -1,12 +0,24 @@

import percy from './percy-info.js';
import request from './request.js'; // Post snapshot data to the snapshot endpoint. If the snapshot endpoint responds with a closed
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
exports.postSnapshot = postSnapshot;
var _percyInfo = _interopRequireDefault(require("./percy-info.js"));
var _request = _interopRequireDefault(require("./request.js"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
// Post snapshot data to the snapshot endpoint. If the snapshot endpoint responds with a closed
// error message, signal that Percy has been disabled.
export async function postSnapshot(options, params) {
async function postSnapshot(options, params) {
let query = params ? `?${new URLSearchParams(params)}` : '';
await request.post(`/percy/snapshot${query}`, options).catch(err => {
await _request.default.post(`/percy/snapshot${query}`, options).catch(err => {
var _err$response, _err$response$body, _err$response$body$bu;
if ((_err$response = err.response) !== null && _err$response !== void 0 && (_err$response$body = _err$response.body) !== null && _err$response$body !== void 0 && (_err$response$body$bu = _err$response$body.build) !== null && _err$response$body$bu !== void 0 && _err$response$body$bu.error) {
percy.enabled = false;
_percyInfo.default.enabled = false;
} else {

@@ -17,2 +29,4 @@ throw err;

}
export default postSnapshot;
var _default = postSnapshot;
exports.default = _default;

@@ -1,6 +0,21 @@

import percy from './percy-info.js'; // Helper to send a request to the local CLI API
"use strict";
export async function request(path, options = {}) {
let response = await request.fetch(`${percy.address}${path}`, options); // maybe parse response body as json
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
exports.request = request;
var _percyInfo = _interopRequireDefault(require("./percy-info.js"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
// Helper to send a request to the local CLI API
async function request(path, options = {}) {
let response = await request.fetch(`${_percyInfo.default.address}${path}`, options); // maybe parse response body as json
if (typeof response.body === 'string' && response.headers['content-type'] === 'application/json') {

@@ -49,3 +64,3 @@ try {

default: http
} = await import('http');
} = await Promise.resolve().then(() => _interopRequireWildcard(require('http')));
return new Promise((resolve, reject) => {

@@ -66,2 +81,3 @@ http.request(url, options).on('response', response => {

export default request;
var _default = request;
exports.default = _default;
{
"name": "@percy/sdk-utils",
"version": "1.1.0",
"version": "1.1.1",
"license": "MIT",

@@ -24,3 +24,2 @@ "repository": {

"browser": "./dist/bundle.js",
"type": "module",
"exports": {

@@ -51,16 +50,7 @@ ".": "./dist/index.js",

"external": [
"@percy/logger",
"test/server(.js)?"
],
"output": {
"globals": {
"@percy/logger": "PercySDKUtils.logger"
}
}
]
}
},
"dependencies": {
"@percy/logger": "1.1.0"
},
"gitHead": "bf551295a8a618502bb2db92ff302e19dc956b51"
"gitHead": "d74af6a294f89fcb23c4ec598bb68a884ce47907"
}
(function() {
this["null"] = this["null"] || {};
this.PercySDKUtils.TestHelpers = (function (logger, utils) {
this.PercySDKUtils.TestHelpers = (function (require$$0) {
'use strict';

@@ -14,57 +14,9 @@

var logger__default = /*#__PURE__*/_interopDefaultLegacy(logger);
var utils__default = /*#__PURE__*/_interopDefaultLegacy(utils);
var require$$0__default = /*#__PURE__*/_interopDefaultLegacy(require$$0);
const {
assign,
entries
} = Object; // matches ansi escape sequences
const utils = require$$0__default["default"];
const ANSI_REG = new RegExp('[\\u001B\\u009B][[\\]()#;?]*((?:(?:[a-zA-Z\\d]*(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)' + '|(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))', 'g'); // color names by ansi escape code
const ANSI_COLORS = {
'91m': 'red',
'32m': 'green',
'93m': 'yellow',
'34m': 'blue',
'95m': 'magenta',
'90m': 'grey'
}; // colorize each line of a string using an ansi escape sequence
const LINE_REG = /^.*$/gm;
function colorize(code, str) {
return str.replace(LINE_REG, line => `\u001b[${code}${line}\u001b[39m`);
} // map ansi colors to bound colorize functions
entries(ANSI_COLORS).reduce((colors, _ref) => {
let [code, name] = _ref;
return assign(colors, {
[name]: colorize.bind(null, code)
});
}, {});
const ELAPSED_REG = /\s\S*?\(\d+ms\)\S*/;
const NEWLINE_REG = /\r\n/g;
const LASTLINE_REG = /\n$/;
function sanitizeLog(str) {
let {
ansi,
elapsed
} = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
// normalize line endings
str = str.replace(NEWLINE_REG, '\n'); // strip ansi colors
if (!ansi) str = str.replace(ANSI_REG, ''); // strip elapsed time
if (!elapsed) str = str.replace(ELAPSED_REG, ''); // strip trailing line endings
return str.replace(LASTLINE_REG, '');
}
function spy(object, method, func) {
function stub(object, method, func) {
if (object[method].restore) object[method].restore();
let spy = Object.assign(function spy() {
let stub = object[method] = Object.assign(function stub() {
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {

@@ -74,117 +26,54 @@ args[_key] = arguments[_key];

spy.calls.push(args);
stub.calls.push(args);
if (func) return func.apply(this, args);
}, {
restore: () => object[method] = spy.originalValue,
reset: () => (spy.calls.length = 0) || spy,
restore: () => object[method] = stub.originalValue,
reset: () => (stub.calls.length = 0) || stub,
originalValue: object[method],
calls: []
});
object[method] = spy;
return spy;
}
return stub;
} // matches ansi escape sequences
const {
Logger,
loglevel
} = logger__default["default"];
const helpers$1 = {
stdout: [],
stderr: [],
loglevel,
async mock() {
let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
helpers$1.reset();
const ANSI_REG = new RegExp('[\\u001B\\u009B][[\\]()#;?]*((?:(?:[a-zA-Z\\d]*(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)' + '|(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))', 'g'); // strips a log message of excessive newlines and asni escape sequences
if (options.level) {
loglevel(options.level);
}
function sanitizeLog(str) {
return str.replace(/\r\n/g, '\n').replace(ANSI_REG, '').replace(/\n$/, '');
}
const helpers = {
async setup() {
utils.percy.version = '';
delete utils.percy.config;
delete utils.percy.enabled;
delete utils.percy.domScript;
delete process.env.PERCY_SERVER_ADDRESS;
await helpers.call('server.mock');
await helpers.logger.mock();
},
async teardown() {
if (process.env.__PERCY_BROWSERIFIED__) {
spy(Logger.prototype, 'write', function (lvl, msg) {
let stdio = lvl === 'info' ? 'stdout' : 'stderr';
helpers$1[stdio].push(sanitizeLog(msg, options));
return this.write.originalValue.call(this, lvl, msg);
});
spy(console, 'log');
spy(console, 'warn');
spy(console, 'error');
for (let m of ['warn', 'error', 'log']) {
var _console$m$restore, _console$m;
(_console$m$restore = (_console$m = console[m]).restore) === null || _console$m$restore === void 0 ? void 0 : _console$m$restore.call(_console$m);
}
} else {
let {
Writable
} = await import('stream');
for (let io of ['stdout', 'stderr']) {
var _process$io$write$res, _process$io$write;
for (let stdio of ['stdout', 'stderr']) {
Logger[stdio] = Object.assign(new Writable(), {
columns: options.isTTY ? 100 : null,
isTTY: options.isTTY,
cursorTo() {},
clearLine() {},
_write(chunk, encoding, callback) {
helpers$1[stdio].push(sanitizeLog(chunk.toString(), options));
callback();
}
});
(_process$io$write$res = (_process$io$write = process[io].write).restore) === null || _process$io$write$res === void 0 ? void 0 : _process$io$write$res.call(_process$io$write);
}
}
},
reset(soft) {
if (soft) loglevel('info');else delete Logger.instance;
helpers$1.stdout.length = 0;
helpers$1.stderr.length = 0;
if (console.log.reset) {
console.log.reset();
console.warn.reset();
console.error.reset();
}
return helpers.call('server.close');
},
dump() {
let msgs = Array.from(Logger.instance && Logger.instance.messages || []);
if (!msgs.length) return;
let log = m => process.env.__PERCY_BROWSERIFIED__ ? console.log.and ? console.log.and.originalFn(m) : console.log(m) : process.stderr.write(`${m}\n`);
logger__default["default"].loglevel('debug');
log(logger__default["default"].format('testing', 'warn', '--- DUMPING LOGS ---'));
msgs.reduce((last, _ref) => {
let {
debug,
level,
message,
timestamp
} = _ref;
log(logger__default["default"].format(debug, level, message, timestamp - last));
return timestamp;
}, msgs[0].timestamp);
}
};
const helpers = {
logger: helpers$1,
async setup() {
utils__default["default"].percy.version = '';
delete utils__default["default"].percy.config;
delete utils__default["default"].percy.enabled;
delete utils__default["default"].percy.domScript;
delete process.env.PERCY_SERVER_ADDRESS;
await helpers.call('server.mock');
await helpers$1.mock();
},
teardown: () => helpers.call('server.close'),
getRequests: () => helpers.call('server.requests'),
testReply: (path, reply) => helpers.call('server.reply', path, reply),
testFailure: function () {
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
args[_key2] = arguments[_key2];
}

@@ -199,3 +88,53 @@

mockSite: () => helpers.call('site.mock'),
closeSite: () => helpers.call('site.close')
closeSite: () => helpers.call('site.close'),
logger: {
stdout: [],
stderr: [],
loglevel: utils.logger.loglevel,
async mock() {
helpers.logger.reset();
let capture = err => msg => {
helpers.logger[err ? 'stderr' : 'stdout'].push(sanitizeLog(msg));
};
if (process.env.__PERCY_BROWSERIFIED__) {
// use console[warn|error|log] in browsers
for (let m of ['warn', 'error', 'log']) {
stub(console, m, capture(m !== 'log'));
}
} else {
// use process[stdout|stderr].write in node
for (let io of ['stdout', 'stderr']) {
stub(process[io], 'write', capture(io === 'stderr'));
}
}
},
reset() {
var _utils$logger$remote$;
(_utils$logger$remote$ = utils.logger.remote.socket) === null || _utils$logger$remote$ === void 0 ? void 0 : _utils$logger$remote$.close();
delete utils.logger.loglevel.lvl;
delete utils.logger.log.history;
helpers.logger.stdout.length = 0;
helpers.logger.stderr.length = 0;
if (process.env.__PERCY_BROWSERIFIED__) {
for (let m of ['warn', 'error', 'log']) {
var _console$m$reset, _console$m2;
(_console$m$reset = (_console$m2 = console[m]).reset) === null || _console$m$reset === void 0 ? void 0 : _console$m$reset.call(_console$m2);
}
} else {
for (let io of ['stdout', 'stderr']) {
var _process$io$write$res2, _process$io$write2;
(_process$io$write$res2 = (_process$io$write2 = process[io].write).reset) === null || _process$io$write$res2 === void 0 ? void 0 : _process$io$write$res2.call(_process$io$write2);
}
}
}
}
};

@@ -205,4 +144,4 @@

helpers.call = async function call(event) {
for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
args[_key2 - 1] = arguments[_key2];
for (var _len3 = arguments.length, args = new Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) {
args[_key3 - 1] = arguments[_key3];
}

@@ -271,3 +210,3 @@

context
} = await import('./server.js');
} = await ({});
helpers.context = helpers.context || (await context());

@@ -278,5 +217,7 @@ return helpers.context.call(...arguments);

return helpers;
var helpers_1 = helpers;
})(PercySDKUtils.logger, PercySDKUtils);
return helpers_1;
})(PercySDKUtils);
}).call(window);

@@ -283,0 +224,0 @@

@@ -1,7 +0,33 @@

import logger from '@percy/logger/test/helpers';
import utils from '@percy/sdk-utils';
const utils = require('@percy/sdk-utils');
export const helpers = {
logger,
function stub(object, method, func) {
if (object[method].restore) object[method].restore();
let stub = object[method] = Object.assign(function stub(...args) {
stub.calls.push(args);
if (func) return func.apply(this, args);
}, {
restore: () => (object[method] = stub.originalValue),
reset: () => (stub.calls.length = 0) || stub,
originalValue: object[method],
calls: []
});
return stub;
}
// matches ansi escape sequences
const ANSI_REG = new RegExp((
'[\\u001B\\u009B][[\\]()#;?]*((?:(?:[a-zA-Z\\d]*(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)' +
'|(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))'
), 'g');
// strips a log message of excessive newlines and asni escape sequences
function sanitizeLog(str) {
return str.replace(/\r\n/g, '\n')
.replace(ANSI_REG, '')
.replace(/\n$/, '');
}
const helpers = {
async setup() {

@@ -14,6 +40,15 @@ utils.percy.version = '';

await helpers.call('server.mock');
await logger.mock();
await helpers.logger.mock();
},
teardown: () => helpers.call('server.close'),
async teardown() {
if (process.env.__PERCY_BROWSERIFIED__) {
for (let m of ['warn', 'error', 'log']) console[m].restore?.();
} else {
for (let io of ['stdout', 'stderr']) process[io].write.restore?.();
}
return helpers.call('server.close');
},
getRequests: () => helpers.call('server.requests'),

@@ -27,3 +62,45 @@ testReply: (path, reply) => helpers.call('server.reply', path, reply),

mockSite: () => helpers.call('site.mock'),
closeSite: () => helpers.call('site.close')
closeSite: () => helpers.call('site.close'),
logger: {
stdout: [],
stderr: [],
loglevel: utils.logger.loglevel,
async mock() {
helpers.logger.reset();
let capture = err => msg => {
helpers.logger[err ? 'stderr' : 'stdout']
.push(sanitizeLog(msg));
};
if (process.env.__PERCY_BROWSERIFIED__) {
// use console[warn|error|log] in browsers
for (let m of ['warn', 'error', 'log']) {
stub(console, m, capture(m !== 'log'));
}
} else {
// use process[stdout|stderr].write in node
for (let io of ['stdout', 'stderr']) {
stub(process[io], 'write', capture(io === 'stderr'));
}
}
},
reset() {
utils.logger.remote.socket?.close();
delete utils.logger.loglevel.lvl;
delete utils.logger.log.history;
helpers.logger.stdout.length = 0;
helpers.logger.stderr.length = 0;
if (process.env.__PERCY_BROWSERIFIED__) {
for (let m of ['warn', 'error', 'log']) console[m].reset?.();
} else {
for (let io of ['stdout', 'stderr']) process[io].write.reset?.();
}
}
}
};

@@ -82,2 +159,2 @@

export default helpers;
module.exports = helpers;

@@ -1,7 +0,6 @@

import fs from 'fs';
import url from 'url';
import path from 'path';
const fs = require('fs');
const path = require('path');
// create a testing context for mocking the local percy server and a local testing site
export async function context() {
async function context() {
let { createTestServer } = await import('@percy/core/test/helpers/server');

@@ -68,3 +67,3 @@

ctx.server.websocket(ws => {
ctx.server.websocket('/(logger)?', ws => {
if (!allowSocketConnections) return ws.terminate();

@@ -113,3 +112,3 @@ ws.onmessage = ({ data }) => ctx.server.messages.push(data);

// start a testing server to control a context remotely
export async function start(args) {
async function start(args) {
let { logger } = await import('@percy/logger');

@@ -163,3 +162,3 @@ let { WebSocketServer } = await import('ws');

// stop any existing testing server
export async function stop() {
async function stop() {
let { default: WS } = await import('ws');

@@ -175,3 +174,3 @@

// start & stop a testing server around a command
export async function exec(args) {
async function exec(args) {
let argsep = args.indexOf('--');

@@ -194,6 +193,4 @@ if (argsep < 0) throw new Error('Must supply a command after `--`');

// allow invoking start/stop/exec as CLI commands
const filename = url.fileURLToPath(import.meta.url);
const [program, ...args] = process.argv.slice(1);
if (program === filename || `${program}.js` === filename) {
if (require.main === module) {
const args = process.argv.slice(2);
const run = { start, stop, exec }[args[0]];

@@ -203,8 +200,8 @@

process.stderr.write('usage: node test/server <start|stop|exec>\n');
} else if (!process.send && fs.existsSync(path.join(filename, '../../src'))) {
await import('child_process').then(cp => cp.fork(filename, args, {
} else if (!process.send && fs.existsSync(path.join(__filename, '../../src'))) {
import('child_process').then(cp => cp.fork(__filename, args, {
execArgv: ['--no-warnings', '--loader=../../scripts/loader.js']
}));
} else {
await run(args.slice(1)).catch(console.error);
run(args.slice(1)).catch(console.error);
}

@@ -214,2 +211,2 @@ }

// export the namespace by default
export * as default from './server.js';
module.exports = { context, start, stop, exec };
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