@xec-sh/cli
Version:
Xec: The Universal Shell for TypeScript
243 lines • 7.68 kB
JavaScript
export function deepMerge(target, source, options) {
if (source === null || source === undefined) {
return target;
}
if (target === null || target === undefined) {
return source;
}
if (typeof source !== 'object' || typeof target !== 'object') {
return source;
}
if (Array.isArray(source)) {
if (Array.isArray(target) && source[0] === '$merge') {
return [...target, ...source.slice(1)];
}
return source;
}
const result = { ...target };
for (const key of Object.keys(source)) {
const sourceValue = source[key];
if (options?.skipUndefined && sourceValue === undefined) {
continue;
}
if (sourceValue === '$unset') {
delete result[key];
continue;
}
if (Array.isArray(sourceValue)) {
if (Array.isArray(result[key]) && sourceValue[0] === '$merge') {
result[key] = [...result[key], ...sourceValue.slice(1)];
}
else {
result[key] = sourceValue;
}
}
else if (sourceValue &&
typeof sourceValue === 'object' &&
result[key] &&
typeof result[key] === 'object' &&
!Array.isArray(result[key])) {
result[key] = deepMerge(result[key], sourceValue, options);
}
else {
result[key] = sourceValue;
}
}
return result;
}
export function parseDuration(duration) {
if (typeof duration === 'number') {
return duration;
}
const match = duration.match(/^(\d+)(ms|s|m|h)?$/);
if (!match) {
throw new Error(`Invalid duration format: ${duration}`);
}
const value = parseInt(match[1] || '0', 10);
const unit = match[2] || 'ms';
switch (unit) {
case 'ms':
return value;
case 's':
return value * 1000;
case 'm':
return value * 60 * 1000;
case 'h':
return value * 60 * 60 * 1000;
default:
throw new Error(`Unknown duration unit: ${unit}`);
}
}
export function formatDuration(ms) {
if (ms < 1000) {
return `${ms}ms`;
}
const seconds = Math.floor(ms / 1000);
if (seconds < 60) {
return `${seconds}s`;
}
const minutes = Math.floor(seconds / 60);
if (minutes < 60) {
return `${minutes}m`;
}
const hours = Math.floor(minutes / 60);
return `${hours}h`;
}
export function parseMemorySize(size) {
if (typeof size === 'number') {
return size;
}
const match = size.match(/^(\d+)([A-Z]*)?$/i);
if (!match) {
throw new Error(`Invalid memory size format: ${size}`);
}
const value = parseInt(match[1] || '0', 10);
const unit = (match[2] || 'B').toUpperCase();
switch (unit) {
case 'B':
return value;
case 'K':
case 'KB':
return value * 1024;
case 'M':
case 'MB':
return value * 1024 * 1024;
case 'G':
case 'GB':
return value * 1024 * 1024 * 1024;
default:
throw new Error(`Unknown memory size unit: ${unit}`);
}
}
export function isValidTargetReference(ref) {
if (ref.includes(':')) {
const parts = ref.split(':', 2);
const type = parts[0] || '';
const name = parts[1] || '';
return ['docker', 'pod', 'ssh'].includes(type) && !!name && name.length > 0;
}
if (ref.includes('.')) {
const firstDotIndex = ref.indexOf('.');
const type = ref.substring(0, firstDotIndex);
const name = ref.substring(firstDotIndex + 1);
if (['hosts', 'containers', 'pods', 'local'].includes(type)) {
return !!name && name.length > 0;
}
const commonTLDs = ['com', 'org', 'net', 'io', 'dev', 'app', 'co', 'me', 'info', 'biz'];
const lastDotIndex = ref.lastIndexOf('.');
const possibleTLD = ref.substring(lastDotIndex + 1);
if (commonTLDs.includes(possibleTLD.toLowerCase())) {
return true;
}
const dotCount = (ref.match(/\./g) || []).length;
if (dotCount === 1 && type.match(/^[a-z]+$/) && name.match(/^[a-z][a-z0-9-]*$/)) {
return false;
}
}
if (ref === 'local') {
return true;
}
return ref.length > 0;
}
export function parseTargetReference(ref) {
if (ref === 'local') {
return { type: 'local', isWildcard: false };
}
if (ref.includes(':')) {
const parts = ref.split(':', 2);
const prefix = parts[0] || '';
const name = parts[1] || '';
const typeMap = {
'ssh': 'hosts',
'docker': 'containers',
'pod': 'pods',
'k8s': 'pods'
};
return {
type: typeMap[prefix] || 'auto',
name,
isWildcard: !!name && (name.includes('*') || name.includes('?'))
};
}
if (ref.includes('.')) {
const firstDotIndex = ref.indexOf('.');
const type = ref.substring(0, firstDotIndex);
const name = ref.substring(firstDotIndex + 1);
if (['hosts', 'containers', 'pods'].includes(type)) {
return {
type: type,
name,
isWildcard: !!name && (name.includes('*') || name.includes('?'))
};
}
}
return {
type: 'auto',
name: ref,
isWildcard: ref.includes('*') || ref.includes('?')
};
}
export function matchPattern(pattern, str) {
const regexPattern = pattern
.split('*').map(part => part.split('?').map(escapeRegex).join('.'))
.join('.*');
const regex = new RegExp(`^${regexPattern}$`);
return regex.test(str);
}
function escapeRegex(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}
export function expandBraces(pattern) {
const match = pattern.match(/^(.*)\{([^}]+)\}(.*)$/);
if (!match) {
return [pattern];
}
const [, prefix, items, suffix] = match;
const expanded = [];
if (!items) {
return [pattern];
}
for (const item of items.split(',')) {
const trimmed = item.trim();
const rangeMatch = trimmed.match(/^(\d+)\.\.(\d+)$/);
if (rangeMatch) {
const start = parseInt(rangeMatch[1] || '0', 10);
const end = parseInt(rangeMatch[2] || '0', 10);
for (let i = start; i <= end; i++) {
expanded.push(`${prefix || ''}${i}${suffix || ''}`);
}
}
else {
expanded.push(`${prefix || ''}${trimmed}${suffix || ''}`);
}
}
return expanded.flatMap(item => expandBraces(item));
}
export function flattenObject(obj, prefix = '') {
const flattened = {};
for (const [key, value] of Object.entries(obj)) {
const fullKey = prefix ? `${prefix}.${key}` : key;
if (value && typeof value === 'object' && !Array.isArray(value)) {
Object.assign(flattened, flattenObject(value, fullKey));
}
else {
flattened[fullKey] = value;
}
}
return flattened;
}
export function isCI() {
return !!(process.env['CI'] ||
process.env['GITHUB_ACTIONS'] ||
process.env['GITLAB_CI'] ||
process.env['CIRCLECI'] ||
process.env['JENKINS_URL'] ||
process.env['TEAMCITY_VERSION']);
}
export function getDefaultShell() {
if (process.platform === 'win32') {
return process.env['COMSPEC'] || 'cmd.exe';
}
return process.env['SHELL'] || '/bin/sh';
}
//# sourceMappingURL=utils.js.map