@gasket/utils
Advanced tools
Comparing version 7.0.0-next.23 to 7.0.0-next.25
const defaultsDeep = require('lodash.defaultsdeep'); | ||
const debug = require('diagnostics')('gasket:utils'); | ||
@@ -8,10 +7,8 @@ | ||
* or local-only config file. | ||
* | ||
* @param {object} config - Target config to be normalized | ||
* @param {object} context - Context for applying overrides | ||
* @param {string} context.env - Name of environment | ||
* @param {string} [context.commandId] - Name of command | ||
* @returns {object} config | ||
* @type {import('./index').applyConfigOverrides} | ||
*/ | ||
function applyConfigOverrides(config, { env = '', commandId }) { | ||
function applyConfigOverrides( | ||
config, | ||
{ env = '', commandId } | ||
) { | ||
return defaultsDeep( | ||
@@ -23,2 +20,6 @@ {}, | ||
/** | ||
* Generator function to yield potential configurations | ||
* @type {import('./index').getPotentialConfigs} | ||
*/ | ||
function *getPotentialConfigs({ config, env, commandId }) { | ||
@@ -43,2 +44,8 @@ // Separate environment-specific config from another config | ||
/** | ||
* Generator function to yield sub-environment overrides | ||
* @param {string} env - Environment | ||
* @param {object} environments - Environments object | ||
* @yields {object} - Sub-environment overrides | ||
*/ | ||
function *getSubEnvironmentOverrides(env, environments) { | ||
@@ -59,2 +66,8 @@ const envParts = env.split('.'); | ||
/** | ||
* Generator function to yield development overrides | ||
* @param {boolean} isLocalEnv - Is the environment local | ||
* @param {object} environments - Environments object | ||
* @yields {object} - Development overrides | ||
*/ | ||
function *getDevOverrides(isLocalEnv, environments) { | ||
@@ -65,3 +78,5 @@ // Special case for the local environment, which inherits from the | ||
if (devEnv) { | ||
debug('Including dev/development override due to local environment inheritance'); | ||
debug( | ||
'Including dev/development override due to local environment inheritance' | ||
); | ||
yield devEnv; | ||
@@ -68,0 +83,0 @@ } |
import type { GasketConfig, GasketConfigDefinition, MaybeAsync } from '@gasket/core'; | ||
interface PackageManagerOptions { | ||
/** Name of manager, either `npm` (default) or `yarn` */ | ||
packageManager: string; | ||
/** Target directory where `node_module` should exist */ | ||
dest: string; | ||
} | ||
/** | ||
@@ -7,5 +14,12 @@ * Wrapper class for executing commands for a given package manager | ||
export interface PackageManager { | ||
constructor(options: PackageManagerOptions): void; | ||
/** Name of manager, either `npm` (default) or `yarn` */ | ||
manager: string; | ||
/** Target directory where `node_module` should exist */ | ||
dest: string; | ||
/** | ||
* Executes npm in the application directory `this.dest`. | ||
* This installation can be run multiple times. | ||
* Executes npm in the application directory `this.dest`. This installation | ||
* can be run multiple times. | ||
* | ||
@@ -25,4 +39,4 @@ * @param cmd The command that needs to be executed. | ||
/** | ||
* Executes npm install in the application directory `this.dest`. | ||
* This installation can be run multiple times. | ||
* Executes npm install in the application directory `this.dest`. This | ||
* installation can be run multiple times. | ||
* | ||
@@ -32,3 +46,3 @@ * @param args Additional CLI arguments to pass to `npm`. | ||
*/ | ||
install(args?: Array<string>): Promise<void> | ||
install(args?: Array<string>): Promise<void>; | ||
@@ -42,29 +56,53 @@ /** | ||
*/ | ||
info(args?: Array<string>): Promise<{ data: any, stdout: string }>; | ||
info(args?: Array<string>): Promise<{ data: any; stdout: string }>; | ||
} | ||
export function tryRequire(path: string): object|null; | ||
/** | ||
* Normalize the config by applying any overrides for environments, commands, | ||
* or local-only config file. | ||
* Tries to require a module, but ignores if it is not found. If not found, | ||
* result will be null. | ||
* @example | ||
* const { tryRequire } = require('@gasket/utils'); | ||
* | ||
* @param config - Target config to be normalized | ||
* @param context - Context for applying overrides | ||
* @param context.env - Name of environment | ||
* @param [context.commandId] - Name of command | ||
* @returns config | ||
* let someConfig = tryRequire('../might/be/a/path/to/some/file'); | ||
* | ||
* if(!someConfig) { | ||
* someConfig = require('./default-config') | ||
* } | ||
*/ | ||
export function applyConfigOverrides(config: GasketConfigDefinition, { env, commandId }: { | ||
export function tryRequire(path: string): object | null; | ||
interface ConfigContext { | ||
/** Name of environment */ | ||
env: string; | ||
/** Name of command */ | ||
commandId?: string; | ||
}): GasketConfig; | ||
/** Project root; required if using localeFile */ | ||
} | ||
/** | ||
* Promise friendly wrapper to running a shell command (eg: git, npm, ls) | ||
* which passes back any { stdout, stderr } to the error thrown. | ||
* Normalize the config by applying any overrides for environments, commands, or local-only config file. | ||
*/ | ||
export function applyConfigOverrides( | ||
config: GasketConfigDefinition, | ||
configContext: ConfigContext | ||
): GasketConfig; | ||
export interface Signal { | ||
aborted?: boolean; | ||
addEventListener(type: 'abort', listener: () => void): void; | ||
} | ||
export function getPotentialConfigs( | ||
config: ConfigContext & { | ||
config: GasketConfigDefinition; | ||
} | ||
): Generator<any, any, any>; | ||
/** | ||
* Promise friendly wrapper to running a shell command (eg: git, npm, ls) which | ||
* passes back any { stdout, stderr } to the error thrown. | ||
* | ||
* Options can be passed to the underlying spawn. An additional `signal` option | ||
* can be passed to use AbortController, allowing processes to be killed when | ||
* no longer needed. | ||
* can be passed to use AbortController, allowing processes to be killed when no | ||
* longer needed. | ||
* | ||
@@ -91,15 +129,46 @@ * @example | ||
* } | ||
* | ||
* @param cmd - Binary that is run | ||
* @param [argv] - Arguments passed to npm binary through spawn. | ||
* @param [options] options passed to npm binary through spawn | ||
* @param [options.signal] AbortControl signal allowing process to be canceled | ||
* @param [debug] When present pipes std{out,err} to process.* | ||
* @returns results | ||
*/ | ||
export function runShellCommand(cmd: string, argv?: string[], options?: { | ||
signal?: object; | ||
}, debug?: boolean): Promise<{ stdout: string }>; | ||
export function runShellCommand( | ||
/** Binary that is run */ | ||
cmd: string, | ||
/** Arguments passed to npm binary through spawn. */ | ||
argv?: string[], | ||
/** Options passed to npm binary through spawn */ | ||
options?: { | ||
/** AbortControl signal allowing process to be canceled */ | ||
signal?: Signal; | ||
/** Path to the target app (Default: cwd/appName) */ | ||
cwd?: string; | ||
}, | ||
/** When present pipes std{out,err} to process.* */ | ||
debug?: boolean | ||
): Promise<{ stdout: string }>; | ||
export interface PkgManager { | ||
pkgManager: string; | ||
cmd: string; | ||
flags: string[]; | ||
logMsg: (msg: string) => string; | ||
} | ||
export interface TargetConfig { | ||
environments: string; | ||
} | ||
export interface environments { | ||
dev; | ||
} | ||
export interface ConfigContext { | ||
/** Name of environment */ | ||
env: string; | ||
/** Name of command */ | ||
commandId?: string; | ||
/** Project root; required if using localeFile */ | ||
root?: string; | ||
/** Optional file to load relative to gasket root */ | ||
localFile?: string; | ||
} | ||
export function warnIfOutdated(pkgName: string, currentVersion: string): MaybeAsync<void>; |
@@ -6,11 +6,5 @@ /* eslint-disable no-process-env */ | ||
* Wrapper class for executing commands for a given package manager | ||
* | ||
* @type {PackageManager} | ||
*/ | ||
class PackageManager { | ||
/** | ||
* @param {object} options Options | ||
* @param {string} [options.packageManager] Name of manager, either `npm` (default) or `yarn` | ||
* @param {string} options.dest Target directory where `node_module` should exist | ||
*/ | ||
/** @param {import('./index').PackageManagerOptions} options - Options */ | ||
constructor({ packageManager = 'npm', dest }) { | ||
@@ -25,3 +19,2 @@ this.manager = packageManager; | ||
* npm based on process.env. | ||
* | ||
* @param {string[]} argv Precise CLI arguments to pass to `npm`. | ||
@@ -33,11 +26,12 @@ * @param {object} spawnWith Options for child_process.spawn. | ||
static spawnNpm(argv, spawnWith) { | ||
// | ||
// Remark: the npm binary is platform dependent. See: | ||
// https://stackoverflow.com/questions/43230346/error-spawn-npm-enoent/43285131 | ||
// | ||
const npmBin = process.platform === 'win32' | ||
? 'npm.cmd' | ||
: 'npm'; | ||
const npmBin = process.platform === 'win32' ? 'npm.cmd' : 'npm'; | ||
return runShellCommand(npmBin, argv, spawnWith, !!process.env.GASKET_DEBUG_NPM); | ||
return runShellCommand( | ||
npmBin, | ||
argv, | ||
spawnWith, | ||
!!process.env.GASKET_DEBUG_NPM | ||
); | ||
} | ||
@@ -49,3 +43,2 @@ | ||
* npm based on process.env. | ||
* | ||
* @param {string[]} argv Precise CLI arguments to pass to `npm`. | ||
@@ -57,3 +50,2 @@ * @param {object} spawnWith Options for child_process.spawn. | ||
static spawnYarn(argv, spawnWith) { | ||
// | ||
// Just like the `npm` binary, the `yarn` binary is different on windows | ||
@@ -63,8 +55,10 @@ // than it's on unix system. | ||
// See: https://github.com/yarnpkg/yarn/tree/master/bin | ||
// | ||
const yarnBin = process.platform === 'win32' | ||
? 'yarn.cmd' | ||
: 'yarn'; | ||
const yarnBin = process.platform === 'win32' ? 'yarn.cmd' : 'yarn'; | ||
return runShellCommand(yarnBin, argv, spawnWith, !!process.env.GASKET_DEBUG_YARN); | ||
return runShellCommand( | ||
yarnBin, | ||
argv, | ||
spawnWith, | ||
!!process.env.GASKET_DEBUG_YARN | ||
); | ||
} | ||
@@ -75,3 +69,2 @@ | ||
* This installation can be run multiple times. | ||
* | ||
* @param {string} cmd The command that needs to be executed. | ||
@@ -86,3 +79,2 @@ * @param {string[]} args Additional CLI arguments to pass to `npm`. | ||
if (this.manager === 'npm') { | ||
// | ||
// Given that we are spawning `npm` in a child process a number of | ||
@@ -92,3 +84,2 @@ // valid TTY options need to be disabled to get proper output | ||
// Remark: should we make this the default in ./npm? | ||
// | ||
const argv = [ | ||
@@ -113,3 +104,5 @@ '--loglevel', 'info', | ||
return Promise.reject(new Error(`Package manager ${this.manager} is not supported by Gasket`)); | ||
return Promise.reject( | ||
new Error(`Package manager ${this.manager} is not supported by Gasket`) | ||
); | ||
} | ||
@@ -119,3 +112,2 @@ | ||
* Executes npm link in the application directory `this.dest`. | ||
* | ||
* @param {string[]} packages Explicit `npm` packages to link locally. | ||
@@ -132,3 +124,2 @@ * @returns {Promise} promise | ||
* This installation can be run multiple times. | ||
* | ||
* @param {string[]} args Additional CLI arguments to pass to `npm`. | ||
@@ -146,3 +137,2 @@ * @returns {Promise} promise | ||
* Executes yarn or npm info, and returns parsed JSON data results. | ||
* | ||
* @param {string[]} args Additional CLI arguments to pass to `npm`. | ||
@@ -149,0 +139,0 @@ * @returns {Promise<object>} stdout and data |
@@ -5,39 +5,3 @@ /* eslint-disable max-params */ | ||
/** | ||
* Promise friendly wrapper to running a shell command (eg: git, npm, ls) | ||
* which passes back any { stdout, stderr } to the error thrown. | ||
* | ||
* Options can be passed to the underlying spawn. An additional `signal` option | ||
* can be passed to use AbortController, allowing processes to be killed when | ||
* no longer needed. | ||
* | ||
* @example | ||
* const { runShellCommand } = require('@gasket/utils'); | ||
* | ||
* async function helloWorld() { | ||
* await runShellCommand('echo', ['hello world']); | ||
* } | ||
* | ||
* @example | ||
* // With timeout using AbortController | ||
* | ||
* const { runShellCommand } = require('@gasket/utils'); | ||
* const AbortController = require('abort-controller'); | ||
* | ||
* async function helloWorld() { | ||
* const controller = new AbortController(); | ||
* // abort the process after 60 seconds | ||
* const id = setTimeout(() => controller.abort(), 60000); | ||
* await runShellCommand('long-process', ['something'], { signal: controller.signal }); | ||
* clearTimeout(id); | ||
* } | ||
* | ||
* @param {string} cmd Binary that is run | ||
* @param {string[]} [argv] Arguments passed to npm binary through spawn. | ||
* @param {object} [options] Options passed to npm binary through spawn | ||
* @param {object} [options.signal] AbortControl signal allowing process to be canceled | ||
* @param {boolean} [debug] When present pipes std{out,err} to process.* | ||
* @returns {Promise} A promise represents if command succeeds or fails. | ||
* @public | ||
*/ | ||
/** @type {import('./index').runShellCommand} */ | ||
function runShellCommand(cmd, argv, options = {}, debug = false) { | ||
@@ -49,3 +13,8 @@ const { signal, ...opts } = options; | ||
if (signal && signal.aborted) { | ||
return Promise.reject(Object.assign(new Error(`${cmd} was aborted before spawn`), { argv, aborted: true })); | ||
return Promise.reject( | ||
Object.assign(new Error(`${cmd} was aborted before spawn`), { | ||
argv, | ||
aborted: true | ||
}) | ||
); | ||
} | ||
@@ -81,11 +50,13 @@ | ||
child.on('close', code => { | ||
child.on('close', (code) => { | ||
if (code !== 0) { | ||
return reject(Object.assign(new Error(`${cmd} exited with non-zero code`), { | ||
argv, | ||
stdout, | ||
stderr, | ||
aborted, | ||
code | ||
})); | ||
return reject( | ||
Object.assign(new Error(`${cmd} exited with non-zero code`), { | ||
argv, | ||
stdout, | ||
stderr, | ||
aborted, | ||
code | ||
}) | ||
); | ||
} | ||
@@ -92,0 +63,0 @@ |
@@ -1,17 +0,2 @@ | ||
/** | ||
* Tries to require a module, but ignores if it is not found. | ||
* If not found, result will be null. | ||
* | ||
* @example | ||
* const { tryRequire } = require('@gasket/utils'); | ||
* | ||
* let someConfig = tryRequire('../might/be/a/path/to/some/file'); | ||
* | ||
* if(!someConfig) { | ||
* someConfig = require('./default-config') | ||
* } | ||
* | ||
* @param {string} path - Module to import | ||
* @returns {object} module | ||
*/ | ||
/** @type {import('./index').tryRequire} */ | ||
function tryRequire(path) { | ||
@@ -18,0 +3,0 @@ try { |
/** | ||
* Tries to require.resolve a module, but ignores if it is not found. | ||
* If not found, result will be null. | ||
* | ||
* @example | ||
@@ -18,6 +17,6 @@ * const { tryResolve } = require('@gasket/utils'); | ||
* @private | ||
* @param {string} modulePath - Module to import | ||
* @param {object} options - Paths to search for the module | ||
* @returns {string} module path | ||
*/ | ||
* @param {string} modulePath - Module to import | ||
* @param {object} options - Paths to search for the module | ||
* @returns {string} module path | ||
*/ | ||
function resolve(modulePath, options) { | ||
@@ -28,6 +27,6 @@ return require.resolve(modulePath, options); | ||
/** | ||
* @param {string} modulePath - Module to import | ||
* @param {object} options - Paths to search for the module | ||
* @returns {string} module path | ||
*/ | ||
* @param {string} modulePath - Module to import | ||
* @param {object} options - Paths to search for the module | ||
* @returns {string} module path | ||
*/ | ||
function tryResolve(modulePath, options) { | ||
@@ -34,0 +33,0 @@ try { |
@@ -28,3 +28,3 @@ const runShellCommand = require('./run-shell-command'); | ||
* @param {object} cache - cache object | ||
* @returns {string} - latest version of the package | ||
* @returns {Promise<string>} - latest version of the package | ||
*/ | ||
@@ -47,2 +47,3 @@ async function getLatestVersion(pkgName, currentTime, cache) { | ||
} catch (error) { | ||
// eslint-disable-next-line no-console | ||
console.error('Error fetching latest version:', error); | ||
@@ -74,6 +75,8 @@ } | ||
if (typeof latestVersion === 'string' && semver.gt(latestVersion, currentVersion)) { | ||
// eslint-disable-next-line no-console | ||
console.warn( | ||
` ${chalk.yellow('›')} Warning: ${pkgName} update available from ${chalk.green(latestVersion)} to ${chalk.green(currentVersion)}` | ||
` ${chalk.yellow('›')} ` + | ||
`Warning: ${pkgName} update available from ${chalk.green(latestVersion)} to ${chalk.green(currentVersion)}` | ||
); | ||
} | ||
}; |
{ | ||
"name": "@gasket/utils", | ||
"version": "7.0.0-next.23", | ||
"version": "7.0.0-next.25", | ||
"description": "Reusable utilities for Gasket internals", | ||
@@ -17,4 +17,6 @@ "main": "lib", | ||
"test:coverage": "jest --coverage", | ||
"posttest": "npm run lint", | ||
"docs": "jsdoc2md --plugin @godaddy/dmd --files lib/*.js > docs/api.md" | ||
"posttest": "npm run lint && npm run typecheck", | ||
"docs": "jsdoc2md --plugin @godaddy/dmd --files lib/*.js > docs/api.md", | ||
"typecheck": "tsc", | ||
"typecheck:watch": "tsc --watch" | ||
}, | ||
@@ -42,2 +44,3 @@ "repository": { | ||
"dependencies": { | ||
"chalk": "^4.1.2", | ||
"concat-stream": "^2.0.0", | ||
@@ -49,3 +52,3 @@ "diagnostics": "^2.0.2", | ||
"devDependencies": { | ||
"@gasket/core": "^7.0.0-next.23", | ||
"@gasket/core": "^7.0.0-next.25", | ||
"@godaddy/dmd": "^1.0.4", | ||
@@ -55,3 +58,3 @@ "abort-controller": "^3.0.0", | ||
"eslint": "^8.56.0", | ||
"eslint-config-godaddy": "^7.0.2", | ||
"eslint-config-godaddy": "^7.1.0", | ||
"eslint-plugin-jest": "^27.6.3", | ||
@@ -61,3 +64,4 @@ "eslint-plugin-json": "^3.1.0", | ||
"jest": "^29.7.0", | ||
"jsdoc-to-markdown": "^7.1.0" | ||
"jsdoc-to-markdown": "^7.1.0", | ||
"typescript": "^5.4.5" | ||
}, | ||
@@ -67,6 +71,8 @@ "eslintConfig": { | ||
"godaddy", | ||
"plugin:jest/recommended" | ||
"plugin:jest/recommended", | ||
"plugin:jsdoc/recommended-typescript-flavor" | ||
], | ||
"plugins": [ | ||
"unicorn" | ||
"unicorn", | ||
"jsdoc" | ||
], | ||
@@ -80,3 +86,3 @@ "rules": { | ||
], | ||
"gitHead": "0ba753c8764138e300be1c464065280bcc801239" | ||
"gitHead": "0782b4f4d07d18fb6bd44ecaab3e6bdafd6d4c9d" | ||
} |
28308
546
5
12
+ Addedchalk@^4.1.2
+ Addedansi-styles@4.3.0(transitive)
+ Addedchalk@4.1.2(transitive)
+ Addedcolor-convert@2.0.1(transitive)
+ Addedcolor-name@1.1.4(transitive)
+ Addedhas-flag@4.0.0(transitive)
+ Addedsupports-color@7.2.0(transitive)