/*
* 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 * as os from 'node:os'
import * as path from 'node:path'
// ============================================================================
/**
* Represents a map of substitution values used by Liquid templates.
*
* @remarks
* Values can be strings for simple substitutions or arrays for multi-line
* content. Array values are typically joined with newlines when rendered.
*
* Common use cases:
*
*
* - Properties: User-defined configuration values from
*
xpack.properties.
* - Matrix parameters: Template expansion variables from
*
matrix definitions.
* - Configuration data: Build-specific settings and metadata.
*
*
* Templates access these values via namespaces like `properties.foo`,
* `matrix.arch`, etc., with the Liquid Drop pattern providing lazy
* evaluation and nested substitution support.
*/
export type LiquidSubstitutionsStrings = Record
/**
* Defines the substitution variables available to Liquid templates.
*
* @remarks
* This interface mirrors a subset of Node.js environment, operating
* system, and path information, along with package-specific configuration
* values.
*
* Variable hierarchy and scoping:
*
*
* - Base variables (
env, os,
* path): Available globally, initialized once
* from Node.js runtime at startup.
* - Package variables: Added when processing
*
package.json, contains
* package metadata accessible via package.name,
* package.version,
* etc.
* - Properties: User-defined values from
*
xpack.properties, accessible via
* properties.key.
* - Configuration: Build configuration metadata, available when
* processing configuration-specific templates via
*
configuration.name,
* etc.
* - Matrix: Template expansion parameters, scoped to individual
* expanded instances, accessible via
matrix.key.
*
*
* Variables are inherited and extended through the hierarchy:
*
*
* - package actions use package properties
* - configuration actions use:
*
* - package actions
* - actions inherited from parent configurations, recursively,
* in order of inheritance
* - configuration properties
*
*
*
*
* This ensures templates have access to appropriate
* context without exposing unrelated data.
*/
export interface LiquidSubstitutionsVariables {
/**
* Process environment variables from the current execution context.
*
* @remarks
* Provides access to all environment variables via `env.VARIABLE_NAME`
* in templates. Common uses include accessing `PATH`, `HOME`, `USER`, or
* custom variables set by build scripts.
*
* See {@link https://nodejs.org/dist/latest-v16.x/docs/api/process.html#process_process_env | Node.js process.env documentation}
*/
env: NodeJS.ProcessEnv
/**
* Operating system information from Node.js os module.
*
* @remarks
* Provides platform detection and system information for cross-platform
* template logic. Common uses include conditional compilation, path
* construction, and platform-specific configuration.
*
* Key properties for cross-platform templates:
*
*
* os.platform: Detect OS ('darwin', 'linux', 'win32').
* os.arch: Detect CPU architecture ('x64', 'arm64',
* etc.).
* os.EOL: Use correct line endings for generated files.
* os.homedir: Reference user's home folder portably.
*
*
* See {@link https://nodejs.org/dist/latest-v16.x/docs/api/os.html | Node.js os module documentation}
*/
os: {
/**
* The operating system-specific end-of-line marker.
*
* \\n on POSIX
* \\r\\n on Windows
*
*/
EOL: string
/**
* Possible values are 'arm', 'arm64', 'ia32', 'mips', 'mipsel',
* 'ppc', 'ppc64', 's390', 's390x', 'x32', and 'x64'.
*/
arch: string
/**
* Contains commonly used operating system-specific constants
* for error codes, process signals, and so on. The specific
* constants defined are described in
* {@link https://nodejs.org/dist/latest-v16.x/docs/api/os.html#os_os_constants_1 | OS constants}
*/
constants: {
signals: Record
errno: Record
}
/**
* An array of objects containing information about
* each logical CPU core.
*/
cpus: os.CpuInfo[]
/**
* A string identifying the endianness of the CPU
* for which the Node.js binary was compiled.
*
* Possible values are 'BE' for big endian and 'LE' for little endian.
*/
endianness: 'BE' | 'LE'
/**
* The string path of the current user's home folder.
*/
homedir: string
/**
* The host name of the operating system as a string.
*/
hostname: string
/**
* A string identifying the operating system platform.
* Possible values are 'aix', 'darwin', 'freebsd', 'linux', 'openbsd',
* 'sunos', and 'win32'.
*/
platform: NodeJS.Platform
/**
* The operating system as a string.
*/
release: string
/**
* Returns the operating system's default folder for
* temporary files as a string.
*/
tmpdir: string
/**
* Returns the operating system name as returned by uname(3).
* For example, it returns 'Linux' on Linux, 'Darwin' on macOS,
* and 'Windows_NT' on Windows.
*/
type: string
/**
* Returns a string identifying the kernel version.
*
* On POSIX systems, the operating system release is determined
* by calling `uname(3)`. On Windows, `RtlGetVersion()` is used,
* and if it is not available, `GetVersionExW()` will be used.
*/
version: string
}
/**
* Path separators and delimiters from Node.js path module.
*
* @remarks
* Provides platform-specific path constants for building file paths in
* templates. Use these to construct paths that work correctly on all
* platforms.
*
* Available constants:
*
*
* path.sep: Platform-specific path separator (/ or \).
* path.delimiter: Platform-specific PATH delimiter
* (; or :).
* path.posix.*: Force POSIX conventions regardless
of platform.
* path.win32.*: Force Windows conventions regardless
of platform.
*
*
* Note: For path manipulation, prefer using Liquid filters like
* `path_join`, `path_dirname`, etc., which handle cross-platform concerns
* automatically.
*
* See [Node.js path module documentation](https://nodejs.org/dist/latest-v16.x/docs/api/path.html)
*/
path: {
/**
* Provides the platform-specific path delimiter:
*
* ; for Windows
* : for POSIX
*
*/
delimiter: string
/**
* Provides the platform-specific path segment separator:
*
* \\ on Windows
* / on POSIX
*
*/
sep: string
win32: {
delimiter: string
sep: string
}
posix: {
delimiter: string
sep: string
}
}
/**
* The package metadata exposed to Liquid templates.
*
* @remarks
* Contains the entire `package.json` content, allowing templates to access
* package name, version, description, dependencies, and xpack-specific
* metadata.
*
* Common template patterns:
*
*
* \{\{ package.name \}\}: Package name for generated
* files.
* \{\{ package.version \}\}: Version string for
* documentation.
* \{\{ package.xpack.properties.key \}\}: Access xpack
* properties.
*
*
* Undefined when processing templates outside of a package context.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
package?: any
/**
* The build configuration exposed to Liquid templates.
*
* @remarks
* Available only when processing templates within a build configuration
* context (actions, dependencies, properties belonging to a specific
* configuration).
*
* Contains the configuration name and all configuration properties,
* allowing templates to reference the current build context:
*
*
* \{\{ configuration.name \}\}: The build configuration
* name.
* \{\{ configuration.properties.key \}\}:
* Configuration-specific
* settings.
*
*
* Undefined when processing package-level templates.
*/
configuration?: {
name: string
// eslint-disable-next-line @typescript-eslint/no-explicit-any
[key: string]: any
}
/**
* The properties map used for substitutions.
*
* @remarks
* User-defined configuration values from `xpack.properties`
* in `package.json`.
* Provides a namespace for custom template variables without polluting
* the global scope.
*
* Properties support nested substitutions: a property value can reference
* other properties, package metadata, or system variables using Liquid
* syntax. The Liquid Drop pattern ensures recursive evaluation.
*
* Access via `{{ properties.key }}` in templates.
*/
properties: LiquidSubstitutionsStrings
/**
* Optional matrix parameters used for template expansion.
*
* @remarks
* Available only for actions or configurations generated from templates
* with matrix definitions. Each expanded instance receives a specific
* combination of matrix values.
*
* Matrix parameters enable generating multiple similar actions or
* configurations from a single template definition. For example, a matrix
* with `arch: ['x64', 'arm64']` and `os: ['linux', 'darwin']` generates
* 4 instances (x64-linux, x64-darwin, arm64-linux, arm64-darwin).
*
* Access via `{{ matrix.key }}` in templates. Scoped to the individual
* expanded instance, ensuring isolation between generated items.
*/
matrix?: LiquidSubstitutionsStrings
}
/**
* The base substitution variables initialised from the current environment.
*
* @remarks
* This constant provides the foundation for all Liquid template processing,
* capturing the runtime environment once at module load time.
*
* Initialization strategy:
*
*
* - Environment variables: Snapshot of process.env at load time.
* - OS information: OS specific definitions (platform, arch,
* etc.).
* - Path constants: Platform-specific separators and delimiters.
* - Properties: Placeholder for package-specific additions.
*
*
* These base variables are shared across all template processing within the
* application and extended with package, configuration, and matrix variables
* as needed. The base object is typically spread into new contexts rather
* than mutated, preserving the original snapshot.
*/
export const liquidSubstitutionsVariablesBase: LiquidSubstitutionsVariables = {
env: process.env,
os: {
EOL: os.EOL,
arch: os.arch(),
constants: {
signals: os.constants.signals,
errno: os.constants.errno,
},
cpus: os.cpus(),
endianness: os.endianness(),
homedir: os.homedir(),
hostname: os.hostname(),
platform: os.platform(),
release: os.release(),
tmpdir: os.tmpdir(),
type: os.type(),
// os.version() available since 12.x
version: os.version(),
},
path: {
delimiter: path.delimiter,
sep: path.sep,
win32: {
delimiter: path.win32.delimiter,
sep: path.win32.sep,
},
posix: {
delimiter: path.posix.delimiter,
sep: path.posix.sep,
},
},
properties: {},
}
// ----------------------------------------------------------------------------