@modernpoacher/deps
Version:
Update NPM package dependencies from the command line
461 lines (407 loc) • 10.9 kB
JavaScript
/**
* @typedef {DepsTypes.Dependencies} Dependencies
* @typedef {DepsTypes.DependencyDescriptor} DependencyDescriptor
* @typedef {DepsTypes.Package} Package
* @typedef {DepsTypes.Configuration} Configuration
*/
import debug from 'debug'
import PATH from '#where-am-i'
import {
join
} from 'node:path'
import {
VERSION,
PLATFORM
} from '#deps/src/common/env'
export const DIRECTORY = '.'
export const REGISTRY = 'https://registry.npmjs.org'
export const AUTHOR = 'Modern Poacher Limited <modernpoacher@modernpoacher.com>'
export const NVM = join(PATH, 'nvm.sh')
const log = debug('@modernpoacher/deps')
log(`\`common\` (${VERSION} - ${PLATFORM}) is awake`)
/**
* @param {string} v
* @returns {string}
*/
export const tidy = (v) => v.replace(/\n{2,}}/gm, String.fromCharCode(10)).trim()
/**
* @param {string} v
* @returns {string}
*/
export const trim = (v) => v.split(String.fromCharCode(10)).map((v) => v.trimEnd()).join(String.fromCharCode(10)).trim()
/**
* @function getSaveProdParameter
*
* Get the `--save-prod` parameter
*
* @param {string} commands commands string
* @returns {string}
*/
export const getSaveProdParameter = (commands) => commands.concat(' --save-prod')
/**
* @function getSaveDevParameter
*
* Get the `--save-dev` parameter
*
* @param {string} commands commands string
* @returns {string}
*/
export const getSaveDevParameter = (commands) => commands.concat(' --save-dev')
/**
* @function getSaveBundleParameter
*
* Get the "save bundle" parameter
*
* @param {string} commands - Current commands string
* @returns {string}
*/
export const getSaveBundleParameter = (commands) => commands.concat(' --save-bundle')
/**
* @function getSaveOptionalParameter
*
* Get the `--save-optional` parameter
*
* @param {string} commands - Current commands string
* @returns {string}
*/
export const getSaveOptionalParameter = (commands) => commands.concat(' --save-optional')
/**
* @function getRegistryParameter
*
* Get the "registry" parameter and argument
*
* @param {string} r - Registry
* @param {string} commands - Current commands string
* @returns {string}
*/
export const getRegistryParameter = (r, commands) => r ? commands.concat(` --registry ${r}`) : commands
/**
* @function getForceParameter
*
* Get the "force" parameter and argument
*
* @param {boolean} f - Force
* @param {string} commands - Current commands string
* @returns {string}
*/
export const getForceParameter = (f, commands) => f ? commands.concat(' --force') : commands
/**
* @function getNoSaveParameter
*
* Get the `--no-save` parameter
*
* @param {boolean} s - Save
* @param {string} commands - Current commands string
* @returns {string}
*/
export const getNoSaveParameter = (s, commands) => s ? commands : commands.concat(' --no-save')
/**
* @function getSaveExactParameter
*
* Get the `--save-exact` parameter
*
* @param {string} commands - Current commands string
* @returns {string}
*/
export const getSaveExactParameter = (commands) => commands.concat(' --save-exact')
/**
* @function getExportPath
*
* Get the export PATH shell script
*
* @param {string} commands - Current commands string
* @returns {string}
*/
export const getExportPath = (commands) => `
export PATH=/usr/local/bin:$PATH &> /dev/null
${commands}
`
/**
* @function getNvm
*
* Get the NVM shell script
*
* @param {string} commands - Current commands string
* @returns {string}
*/
export const getNvm = (commands) => `
bash "${NVM}" 2> /dev/null
${commands}
`
/**
* @function getCommands
*
* Get the installation shell script
*
* @param {string} commands - Current commands string
* @returns {string}
*/
export const getCommands = PLATFORM === 'win32'
? (commands = 'npm i') => tidy(commands)
: (commands = 'npm i') => tidy(getExportPath(getNvm(commands)))
/**
* @function getProdDependencies
*
* Get the production dependencies by destructuring the package or configuration
*
* @param {Package | Configuration} deps
* @returns {Dependencies}
*/
export const getProdDependencies = ({ dependencies = {} } = {}) => dependencies
/**
* @function getDevDependencies
*
* Get the development dependencies by destructuring the package or configuration
*
* @param {Package | Configuration} deps
* @returns {Dependencies}
*/
export const getDevDependencies = ({ devDependencies = {} } = {}) => devDependencies
/**
* @function getOptionalDependencies
*
* Get the optional dependencies by destructuring the package or configuration
*
* @param {Package | Configuration} deps
* @returns {Dependencies}
*/
export const getOptionalDependencies = ({ optionalDependencies = {} } = {}) => optionalDependencies
/**
* @function getBundleDependencies
*
* Get the bundle dependencies by destructuring the package or configuration
*
* @param {Package | Configuration} deps
* @returns {Dependencies}
*/
export const getBundleDependencies = ({ bundleDependencies = {} } = {}) => bundleDependencies
/**
* @function getPeerDependencies
*
* Get the peer dependencies by destructuring the package or configuration
*
* @param {Package | Configuration} deps
* @returns {Dependencies}
*/
export const getPeerDependencies = ({ peerDependencies = {} } = {}) => peerDependencies
/**
* @function getIgnore
*
* Get the ignore flag by destructuring the configuration
*
* @param {Configuration} deps
* @returns {boolean}
*/
export const getIgnore = ({ ignore = false } = {}) => ignore === true
/**
* @function getAuthor
*
* Get the author by destructuring the package or configuration
*
* @param {Package | Configuration} deps
* @returns {string | null}
*/
export const getAuthor = ({ author = '' } = {}) => {
if (typeof author === 'string') return author
if (typeof (author || false) === 'object') {
const {
name: NAME = '',
email: EMAIL = ''
} = author
const name = String(NAME).trim()
const email = String(EMAIL).trim()
return (
name && email
? `${name} <${email}>`
: null
)
}
return null
}
/**
* @function getMessage
*
* Get the message by destructuring the configuration
*
* @param {Configuration} deps
* @returns {string | null}
*/
export const getMessage = ({ message = '' } = {}) => message || null
/**
* @function isPreRelease
*
* Determine whether the dependency is a pre-release with a Regular Expression
*
* @param {string} v
* @returns {boolean}
*/
export const isPreRelease = (v) => /-/.test(v)
/**
* @function isExact
*
* Determine whether the dependency is exact with a Regular Expression
*
* @param {string} v
* @returns {boolean}
*/
export const isExact = (v) => /^\d/.test(v)
/**
* @param {[name: string, version: string]} entry
* @returns {boolean}
*/
function includeVersionIsExact ([name, version]) {
return isExact(version)
}
/**
* @param {[name: string, version: string]} entry
* @returns {boolean}
*/
function excludeVersionIsExact ([name, version]) {
return !isExact(version)
}
/**
* @function getMapToDepsExactVersionFromConfiguration
*
* Produces an array of objects from the entries of `packageDependencies` which have
* exact versions
*
* Entries have already been filtered to exclude non-exact versions
*
* Each entry is mapped to the same package name in `configurationDependencies` if it
* appears there. Otherwise, the `packageDependencies` version is used
*
* @param {Record<string, string>} configurationDependencies
* @returns {(entry: [name: string, version: string]) => {
* name: string,
* version: string
* }}
*/
function getMapToDepsExactVersionFromConfiguration (configurationDependencies) {
/**
* @param {[name: string, version: string]} entry
* @returns {{
* name: string,
* version: string
* }}
*/
return function mapToDepsExactVersionFromConfiguration (entry) {
const [
name,
version
] = entry
return {
name,
version: (
name in configurationDependencies
? configurationDependencies[name]
: version
)
}
}
}
/**
* @function mapToDepsVersion
*
* Produces an array of objects from the entries of `packageDependencies` which do not have
* exact versions
*
* Where the version is a pre-release, that version is used. Otherwise the version is
* set to `latest` to ensure that package is updated
*
* @param {[name: string, version: string]} entry
* @returns {{
* name: string,
* version: string
* }}
*/
function mapToDepsVersion (entry) {
const [
name,
version
] = entry
if (isPreRelease(version)) {
return {
name,
version
}
}
return {
name,
version: 'latest'
}
}
/**
* @function getDepsExact
*
* Get an array of dependencies to be installed with the `--save-exact` parameter
*
* @param {Dependencies} packageDependencies - Package dependencies
* @param {Dependencies} configurationDependencies - Configuration dependencies
* @returns {DependencyDescriptor[]}
*/
export function getDepsExact (packageDependencies, configurationDependencies) {
log('getDepsExact')
return (
Object.entries(packageDependencies)
.filter(includeVersionIsExact)
.map(getMapToDepsExactVersionFromConfiguration(configurationDependencies))
)
}
/**
* @function getDeps
*
* Get an array of dependencies to be installed
*
* @param {Dependencies} packageDependencies - Package dependencies
* @returns {DependencyDescriptor[]}
*/
export function getDeps (packageDependencies) {
log('getDeps')
return (
Object.entries(packageDependencies)
.filter(excludeVersionIsExact)
.map(mapToDepsVersion)
)
}
/**
* @function normalizeCommands
*
* Normalise the commands string
*
* @param {string} commands
* @returns {string}
*/
export function normalizeCommands (commands) {
const s = String.fromCharCode(32)
while (/\s{2,} | \n+/.test(commands)) {
commands = commands.replace(/\s{2,}/gm, s).replace(/\n+/gm, s)
}
return (
commands.trim()
)
}
/**
* @function transformDependency
*
* Transform by destructuring the value
*
* @param {DependencyDescriptor | { name?: string, version?: string }} dependencyDescriptor
* @returns {string}
*/
export const transformDependency = ({ name = '@modernpoacher/deps', version = 'latest' } = {}) => `${name}@${version}`
/**
* @function transform
*
* Transform the parameter to a string
*
* @param {DependencyDescriptor | DependencyDescriptor[]} value
* @returns {string}
*/
export function transform (value) {
log('transform')
return (
Array.isArray(value)
? value.map(transformDependency).join(String.fromCharCode(32)).trim()
: transformDependency(value)
)
}