xpm
Version:
The xPack project manager command line tool
152 lines (142 loc) • 5.28 kB
text/typescript
/*
* This file is part of the xPack project (http://xpack.github.io).
* Copyright (c) 2021-2026 Liviu Ionescu. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software
* for any purpose is hereby granted, under the terms of the MIT license.
*
* If a copy of the license was not distributed with this file, it can
* be obtained from https://opensource.org/license/mit.
*/
// ----------------------------------------------------------------------------
import { PlatformDetector } from '../classes/platform-detector.js'
// ============================================================================
/**
* Extracts an error message string from an unknown error value.
*
* @remarks
* This utility handles error values of any type, extracting the message
* property from `Error` instances or converting other types to strings.
* Useful for consistent error reporting when the error type is unknown.
*
* TypeScript's catch clause types errors as `unknown` for safety, since
* JavaScript allows throwing any value (not just `Error` instances). This
* function provides a type-safe way to extract a message string:
*
* <ul>
* <li><b>For Error instances:</b> Returns the <code>message</code>
* property.</li>
* <li><b>For other types:</b> Converts to string using <code>String()</code>,
* which handles
* primitives, objects with <code>toString()</code>, <code>null</code>,
* and <code>undefined</code> gracefully.</li>
* </ul>
*
* Common usage pattern:
* ```typescript
* try {
* // code that might throw
* } catch (error) {
* const message = getErrorMessage(error);
* log.error(message);
* }
* ```
*
* @param error - The error value to convert.
* @returns The error message string.
*/
export function getErrorMessage(error: unknown): string {
if (error instanceof Error) {
return error.message
}
return String(error)
}
// ----------------------------------------------------------------------------
/**
* Builds a unique key using the current platform and architecture.
*
* @remarks
* Generates a platform identifier string used for matching binary packages
* to the current system or for platform-specific configuration.
*
* Platform key format: `<platform>-<arch>`
*
* Examples:
*
* <ul>
* <li><code>darwin-x64</code> (macOS on Intel)</li>
* <li><code>darwin-arm64</code> (macOS on Apple Silicon)</li>
* <li><code>linux-x64</code> (Linux on 64-bit Intel/AMD)</li>
* <li><code>win32-x64</code> (Windows on 64-bit)</li>
* </ul>
*
* Architecture coercion rules (when doForce32bit is true):
*
* <ul>
* <li><b>x64 → ia32:</b> Coerces 64-bit Intel/AMD architecture to 32-bit
* on all platforms.</li>
* <li><b>arm64 → arm:</b> Coerces 64-bit ARM architecture to 32-bit
* on all platforms.</li>
* </ul>
*
* This coercion is useful for backward compatibility scenarios where only
* 32-bit binaries are available but can run on 64-bit systems. The
* platform key matches the naming conventions used in binary xPack
* distributions.
*
* @param doForce32bit - Whether to coerce 64-bit architectures to
* their 32-bit equivalents.
* @param platformDetector - The platform detector instance to use. Defaults
* to a new {@link PlatformDetector} instance.
* @returns The platform key in the form `platform-arch`.
*/
export function getPlatformKey({
doForce32bit = false,
platformDetector = new PlatformDetector(),
}: {
doForce32bit?: boolean
platformDetector?: PlatformDetector
} = {}): string {
const { platform, arch } = platformDetector.getPlatformInfo({ doForce32bit })
const key = `${platform}-${arch}`
return key
}
// ----------------------------------------------------------------------------
/**
* Checks whether a string contains Liquid template syntax.
*
* @remarks
* This utility function detects the presence of Liquid template markers
* in a string, indicating that the string requires template processing.
*
* Liquid syntax patterns detected:
*
* <ol>
* <li><b>Variable output:</b> <code>\{\{</code> marks the start of a variable
* interpolation (e.g., <code>\{\{ package.name \}\}</code>).</li>
* <li><b>Control flow:</b> <code>\{%</code> marks the start of a tag
* for logic or iteration (e.g., <code>\{% if condition %\}</code>,
* <code>\{% for item in array %\}</code>).</li>
* </ol>
*
* The function uses a regular expression to efficiently scan the string
* for these markers without needing to check for both patterns separately.
* This is more efficient than calling <code>includes()</code> twice and
* provides a single point of maintenance for Liquid syntax detection logic.
*
* Common usage:
*
* <ul>
* <li>Determine whether to process a value through the Liquid engine.</li>
* <li>Skip unnecessary template evaluation for static strings.</li>
* <li>Validate configuration values for template content.</li>
* </ul>
*
* @param value - The string to check for Liquid syntax.
* @returns <code>true</code> if the string contains Liquid syntax markers,
* <code>false</code> otherwise.
*/
export function hasLiquidSyntax(value: string): boolean {
return /\{\{|\{%/.test(value)
}
// ----------------------------------------------------------------------------