xpm
Version:
The xPack project manager command line tool
268 lines • 9.79 kB
JavaScript
import assert from 'node:assert';
import * as fs from 'node:fs/promises';
import * as path from 'node:path';
import semver from 'semver';
import { ConfigurationError, InputError, PrerequisitesError } from './errors.js';
import { isString } from '../functions/is-something.js';
import { hasLiquidSyntax } from '../functions/utils.js';
export class Package {
packageFolderPath;
jsonPackage;
_log;
constructor({ packageFolderPath, log }) {
assert(packageFolderPath && path.isAbsolute(packageFolderPath), `packageFolderPath must be an absolute path, got: ${packageFolderPath}`);
this._log = log;
this.packageFolderPath = packageFolderPath;
log.trace(`${Package.name}(${packageFolderPath})`);
}
async readPackageDotJson({ withThrow = false, } = {}) {
const jsonFilePath = path.join(this.packageFolderPath, 'package.json');
let fileContent;
try {
fileContent = await fs.readFile(jsonFilePath);
}
catch (error) {
if (withThrow) {
if (error instanceof Error) {
this._log.trace(error.message);
}
throw new InputError(`no package.json in folder ‘${this.packageFolderPath}’`);
}
else {
return undefined;
}
}
try {
this.jsonPackage = JSON.parse(fileContent.toString());
}
catch (error) {
if (withThrow) {
this.jsonPackage = undefined;
if (error instanceof Error) {
this._log.trace(error.message);
}
throw new InputError(`invalid package.json in folder ‘${this.packageFolderPath}’`);
}
else {
return undefined;
}
}
return this.jsonPackage;
}
async rewritePackageDotJson(jsonPackage) {
const log = this._log;
assert(jsonPackage, 'jsonPackage is required');
const jsonString = JSON.stringify(jsonPackage, null, 2) + '\n';
const jsonFilePath = path.join(this.packageFolderPath, 'package.json');
log.trace(`write filePath: '${jsonFilePath}'`);
await fs.writeFile(jsonFilePath, jsonString);
}
isNpmPackage() {
const jsonPackage = this.jsonPackage;
if (!jsonPackage) {
return false;
}
if (jsonPackage.name === undefined || jsonPackage.version === undefined) {
return false;
}
const name = jsonPackage.name.trim();
if (name.length === 0) {
return false;
}
const version = jsonPackage.version.trim();
if (version.length === 0) {
return false;
}
return true;
}
isXpmPackage() {
const jsonPackage = this.jsonPackage;
if (!this.isNpmPackage()) {
return false;
}
if (jsonPackage?.xpack === undefined) {
return false;
}
return true;
}
isBinaryXpmPackage() {
const jsonPackage = this.jsonPackage;
if (!this.isXpmPackage()) {
return false;
}
if (jsonPackage?.xpack.executables ?? jsonPackage?.xpack.bin) {
if (!jsonPackage.xpack.binaries) {
throw new ConfigurationError("doesn't look like a proper binary xpm package, " +
'package.json has no "xpack.binaries"');
}
if (!jsonPackage.xpack.binaries.platforms) {
throw new ConfigurationError("doesn't look like a proper binary xpm package, " +
'package.json has no "xpack.binaries.platforms"');
}
return true;
}
if (jsonPackage?.xpack.binaries) {
if (!jsonPackage.xpack.binaries.platforms) {
throw new ConfigurationError("doesn't look like a proper binary xpm package, " +
'package.json has no "xpack.binaries.platforms"');
}
throw new ConfigurationError("doesn't look like a proper binary xpm package, " +
'package.json has no "xpack.executables"');
}
return false;
}
isNodeModule() {
const jsonPackage = this.jsonPackage;
if (!this.isNpmPackage()) {
return false;
}
if (jsonPackage?.xpack) {
return false;
}
return true;
}
isBinaryNodeModule() {
const jsonPackage = this.jsonPackage;
if (!this.isNodeModule()) {
return false;
}
if (jsonPackage?.bin === undefined) {
return false;
}
return true;
}
hasNpmScripts() {
const jsonPackage = this.jsonPackage;
if (jsonPackage?.scripts !== undefined &&
Object.keys(jsonPackage.scripts).length > 0) {
return true;
}
return false;
}
hasXpmActions() {
const json = this.jsonPackage;
try {
if (json?.xpack.actions !== undefined &&
Object.keys(json.xpack.actions).length > 0) {
return true;
}
if (json?.xpack.buildConfigurations !== undefined &&
Object.keys(json.xpack.buildConfigurations).length > 0) {
for (const buildConfigurationName of Object.keys(json.xpack.buildConfigurations)) {
const buildConfiguration = json.xpack.buildConfigurations[buildConfigurationName];
if (hasLiquidSyntax(buildConfigurationName)) {
const buildConfigurationTemplate = buildConfiguration;
if (buildConfigurationTemplate.template.actions !== undefined &&
Object.keys(buildConfigurationTemplate.template.actions).length >
0) {
return true;
}
}
else {
const buildConfigurationContent = buildConfiguration;
if (buildConfigurationContent.actions !== undefined &&
Object.keys(buildConfigurationContent.actions).length > 0) {
return true;
}
}
}
}
}
catch (error) {
}
return false;
}
getMinimumXpmRequired() {
const log = this._log;
const jsonPackage = this.jsonPackage;
log.trace(`${Package.name}.getMinimumXpmRequired()`);
const version = jsonPackage?.xpack.minimumXpmRequired;
if (version === undefined) {
return undefined;
}
if (!isString(version)) {
return undefined;
}
return version.replace(/-.*$/, '');
}
async checkMinimumXpmRequired({ xpmRootFolderPath, }) {
const log = this._log;
const jsonPackage = this.jsonPackage;
log.trace(`${Package.name}.checkMinimumXpmRequired()`);
if (!this.isXpmPackage()) {
return undefined;
}
const minimumXpmRequired = this.getMinimumXpmRequired();
if (!minimumXpmRequired) {
log.trace('minimumXpmRequired not used, no checks');
return undefined;
}
log.trace(`minimumXpmRequired: ${minimumXpmRequired}`);
let jsonXpmCliPackage;
try {
const cliXpmPackage = new Package({
log,
packageFolderPath: xpmRootFolderPath,
});
jsonXpmCliPackage = await cliXpmPackage.readPackageDotJson({
withThrow: true,
});
}
catch (error) {
if (error instanceof Error) {
log.trace(error.message);
}
else {
log.trace(error);
}
return undefined;
}
assert(jsonXpmCliPackage, 'jsonXpmCliPackage is required');
log.trace(jsonXpmCliPackage.version);
if (!jsonXpmCliPackage.version) {
return undefined;
}
const xpmVersion = semver.clean(jsonXpmCliPackage.version.replace(/-.*$/, ''));
if (!xpmVersion) {
return undefined;
}
if (semver.lt(xpmVersion, minimumXpmRequired)) {
assert(jsonPackage?.name, 'jsonPackage.name is required');
throw new PrerequisitesError(`package '${jsonPackage.name}' ` +
`requires xpm v${minimumXpmRequired} or later, please upgrade`);
}
return minimumXpmRequired;
}
parsePackageSpecifier({ npmPackageSpecifier, }) {
assert(npmPackageSpecifier, 'npmPackageSpecifier is required');
const log = this._log;
let scope;
let name;
let version;
if (npmPackageSpecifier.startsWith('@')) {
const arr = npmPackageSpecifier.split('/');
if (arr.length > 2) {
throw new InputError(`'${npmPackageSpecifier}' not a package name`);
}
scope = arr[0];
if (arr.length > 1) {
const arr2 = arr[1].split('@');
name = arr2[0];
if (arr2.length > 1) {
version = arr2[1];
}
}
}
else {
const arr2 = npmPackageSpecifier.split('@');
name = arr2[0];
if (arr2.length > 1) {
version = arr2[1];
}
}
log.trace(`${npmPackageSpecifier} => ` +
`${scope ?? '?'} ${name ?? '?'} ${version ?? '?'}`);
return { scope, name, version };
}
}
//# sourceMappingURL=package.js.map