UNPKG

xpm

Version:

The xPack project manager command line tool

220 lines (196 loc) 7.51 kB
/* * This file is part of the xPack project (http://xpack.github.io). * Copyright (c) 2017-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 assert from 'node:assert' // https://nodejs.org/docs/latest/api/ import { Logger } from '@xpack/logger' // https://www.npmjs.com/package/semver import semver from 'semver' // ============================================================================ /** * Configuration parameters for constructing a policies instance. * * @remarks * This interface defines the required configuration for creating an * instance of {@link Policies}. Both properties are mandatory. * * The parameters provide the minimum <b>xpm</b> version for policy * evaluation and the logger for diagnostic output. */ export interface PoliciesConstructorParameters { /** * The minimum <b>xpm</b> version to evaluate. */ minVersion?: string /** * The logger instance for output and diagnostics. */ log: Logger } /** * Computes feature policy flags based on a minimum <b>xpm</b> version. * * @remarks * This class derives compatibility flags from a specified minimum * version to preserve legacy behaviour when required. * * Policy versioning allows <b>xpm</b> to evolve its behavior while maintaining * backward compatibility for packages that specify older minimum versions. * Each policy flag represents a breaking change introduced at a specific * <b>xpm</b> version: * * <ul> * <li>Packages with minimumXpmRequired \< version threshold get * legacy behavior.</li> * <li>Packages with minimumXpmRequired \>= version threshold get * new behavior.</li> * </ul> * * This approach ensures that: * * <ol> * <li>Existing packages continue to work with newer <b>xpm</b> versions without * modification.</li> * <li>New packages can opt into modern behavior by specifying a recent * minimumXpmRequired.</li> * <li>Breaking changes are tied to explicit version declarations rather than * <b>xpm</b> installation version.</li> * </ol> * * Policy flags are evaluated once during initialization and cached for the * duration of the operation. */ export class Policies { // -------------------------------------------------------------------------- // Public Members. /** * The minimum <b>xpm</b> version used to derive policy flags. */ minVersion = '0.0.0' /** * Indicates whether npm dependencies are shared across installations. * * @remarks * Legacy behavior (before 0.14.0): npm dependencies were shared in a global * location, similar to how npm itself works with global `node_modules`. * * Modern behavior (0.14.0+): npm dependencies are installed locally per * <b>xpm</b> package, providing better isolation and avoiding version * conflicts. * * Set to `true` for packages with minimumXpmRequired \< 0.14.0. */ shareNpmDependencies = false /** * Indicates whether local `xpacks` folders are non-hierarchical. * * @remarks * Legacy behavior (before 0.16.0): xpacks were stored in a flat structure * within the local `xpacks` folder. * * Modern behavior (0.16.0+): xpacks are organized hierarchically within * the `xpacks` folder, mirroring the scoped package structure (e.g., * `xpacks/@scope/package`). * * Set to `true` for packages with minimumXpmRequired \< 0.16.0. */ nonHierarchicalLocalXpacksFolder = false /** * Indicates whether dependencies are restricted to string-only notation. * * @remarks * Legacy behavior (before 0.16.0): dependencies could only be specified as * strings (e.g., `"@scope/package": "1.0.0"`). * * Modern behavior (0.16.0+): dependencies can be specified as objects with * additional metadata (e.g., platforms, repositories), providing richer * dependency configuration. * * Set to `true` for packages with minimumXpmRequired \< 0.16.0. */ onlyStringDependencies = false /** * Indicates whether `xpm init` templates accept a single parameter. * * @remarks * Legacy behavior (before 0.22.0): init templates accepted only a single * parameter combining template name and optional arguments. * * Modern behavior (0.22.0+): init templates support multiple parameters * for more flexible template initialization and configuration. * * Set to `true` for packages with minimumXpmRequired \< 0.22.0. */ singleParameterXpmInitTemplate = false /** * Indicates whether `xpm init` templates expose top-level properties. * * @remarks * Legacy behavior (before 0.23.0): init templates exposed the configuration * properties both as top-level and also grouped as `properties` * in the liquid substitutions variables. * * Modern behavior (0.23.0+): init templates expose the configuration * properties as `matrix` vs. the liquid substitutions variables as * `properties` providing a clearer structure and avoiding conflicts. * * Set to `true` for packages with minimumXpmRequired \< 0.23.0. */ topPropertiesXpmInitTemplate = false // -------------------------------------------------------------------------- // Constructor. /** * Constructs policy flags based on a minimum <b>xpm</b> version. * * @remarks * The constructor evaluates each policy flag by comparing the provided * minimum version against threshold versions where behavior changed. * * Evaluation process: * * <ol> * <li>Validate that <code>minVersion</code> is a valid semver string.</li> * <li>If invalid, retain default values (all flags false = modern * behavior).</li> * <li>For each policy, use <code>semver.lt()</code> to check if * <code>minVersion</code> is less than * the threshold version.</li> * <li>If <code>minVersion</code> \< threshold, enable legacy behavior * (flag = <code>true</code>).</li> * <li>If <code>minVersion</code> \>= threshold, use modern behavior * (flag = <code>false</code>).</li> * </ol> * * This ensures that packages explicitly declaring their minimum version * get the behavior that was current at that version, while packages * without a valid minimum version default to the most modern behavior. * * @param minVersion - The minimum <b>xpm</b> version to evaluate. * @param log - The logger instance for output and diagnostics. */ constructor({ minVersion, log }: PoliciesConstructorParameters) { log.trace(`${Policies.name}({minVersion: ${String(minVersion)}})`) if (semver.valid(minVersion) !== null) { assert(minVersion) this.minVersion = minVersion this.shareNpmDependencies = semver.lt(this.minVersion, '0.14.0') this.nonHierarchicalLocalXpacksFolder = semver.lt( this.minVersion, '0.16.0' ) this.onlyStringDependencies = semver.lt(this.minVersion, '0.16.0') this.singleParameterXpmInitTemplate = semver.lt(this.minVersion, '0.22.0') this.topPropertiesXpmInitTemplate = semver.lt(this.minVersion, '0.23.0') } log.trace('policies:', this) } } // ----------------------------------------------------------------------------