#!/usr/bin/env node "use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var src_exports = {}; __export(src_exports, { script: () => script }); module.exports = __toCommonJS(src_exports); // src/program.ts var import_commander = require("commander"); var import_cosmiconfig = require("cosmiconfig"); var import_ora = __toESM(require("ora"), 1); var import_gradient_string2 = __toESM(require("gradient-string"), 1); // src/scripts/utils.ts var import_gradient_string = __toESM(require("gradient-string"), 1); var logger = ({ type, section = "", message, err = "", isDebugging = false }) => { const emoji = `\u{1F93C}\u200D\u2640\uFE0F`; const gap = ` => `; const debugMsg = isDebugging ? "debugging:" : ""; const sectionMsg = section.length ? `${section}:` : ""; const firstLine = `codependence:${debugMsg}${sectionMsg}`; const secondLine = message ? `${emoji}${gap}${message}` : ""; if (type === "error") { console.error(import_gradient_string.default.passion(firstLine)); if (secondLine) console.error(secondLine); if (err) console.error(err); } else if (type === "debug") { console.debug(import_gradient_string.default.passion(firstLine)); if (secondLine) console.debug(secondLine); } else if (type === "info") { console.info(import_gradient_string.default.teen(firstLine)); if (secondLine) console.info(secondLine); } else { console.log(import_gradient_string.default.teen(firstLine)); if (secondLine) console.log(secondLine); } }; var writeConsoleMsgs = (packageName, depList) => { if (!depList.length) return; Array.from(depList, ({ name: depName, expected, actual }) => { logger({ type: "log", section: packageName, message: `${depName} version is incorrect!` }); console.log(`\u{1F93C}\u200D\u2640\uFE0F => Found ${actual} and should be ${expected}`); }); }; // src/scripts/core.ts var import_fs = require("fs"); var import_validate_npm_package_name = __toESM(require("validate-npm-package-name"), 1); var import_execa = require("execa"); var import_fast_glob = __toESM(require("fast-glob"), 1); var { sync: glob } = import_fast_glob.default; var constructVersionMap = async ({ codependencies, exec = import_execa.execa, debug = false, yarnConfig = false, isTesting = false, validate = import_validate_npm_package_name.default }) => { const updatedCodeDependencies = await Promise.all( codependencies.map(async (item) => { try { if (typeof item === "object" && Object.keys(item).length === 1) { return item; } else if (typeof item === "string" && item.length > 1 && !item.includes(" ")) { const { validForNewPackages, validForOldPackages, errors } = validate(item); const isValid = [validForNewPackages, validForOldPackages].every((valid) => valid === true); if (!isValid) throw new Error(errors?.join(", ")); const runner = !yarnConfig ? "npm" : "yarn"; const cmd = !yarnConfig ? ["view", item, "version", "latest"] : ["npm", "info", item, "--fields", "version", "--json"]; const { stdout = "" } = await exec(runner, cmd); const version = !yarnConfig ? stdout.replace("\n", "") : JSON.parse(stdout.replace("\n", ""))?.version; if (version) return { [item]: version }; throw `${version}`; } else { throw "invalid item type"; } } catch (err) { if (debug) logger({ type: "error", section: `constructVersionMap`, message: err.toString(), isDebugging: debug }); logger({ type: "error", section: `constructVersionMap`, message: `there was an error retrieving ${item}` }); console.error(`\u{1F93C}\u200D\u2640\uFE0F => Is \u261D\uFE0F a private package? Does that name look correct? \u{1F9D0}`); console.error( `\u{1F93C}\u200D\u2640\uFE0F => Read more about configuring dependencies here: https://github.com/yowainwright/codependence#debugging` ); if (isTesting) return {}; process.exit(1); } }) ); const versionMap = updatedCodeDependencies.reduce( (acc = {}, item) => { const [name] = Object.keys(item); const version = item?.[name]; return { ...acc, ...name && version ? { [name]: version } : {} }; }, {} ); return versionMap; }; var constructVersionTypes = (version) => { const versionCharacters = version.split(""); const [firstCharacter, ...rest] = versionCharacters; const specifier = ["^", "~"].includes(firstCharacter) ? firstCharacter : ""; const hasSpecifier = specifier.length === 1; const characters = rest.join(""); const exactVersion = hasSpecifier ? characters : version; const bumpVersion = version; return { bumpCharacter: specifier, bumpVersion, exactVersion }; }; var constructDepsToUpdateList = (dep = {}, versionMap) => { if (!Object.keys(dep).length) return []; const versionList = Object.keys(versionMap); return Object.entries(dep).map(([name, version]) => { const { exactVersion, bumpCharacter, bumpVersion } = constructVersionTypes(version); return { name, exactVersion, bumpCharacter, bumpVersion }; }).filter(({ name, exactVersion }) => versionList.includes(name) && versionMap[name] !== exactVersion).map(({ name, bumpCharacter, bumpVersion }) => ({ name, actual: bumpVersion, exact: versionMap[name], expected: `${bumpCharacter}${versionMap[name]}` })); }; var constructDeps = (json, depName, depList) => depList?.length ? depList.reduce( (newJson, { name, expected: version }) => { return { ...json[depName], ...newJson, [name]: version }; }, {} ) : json[depName]; var constructJson = (json, depsToUpdate, isDebugging = false) => { const { depList, devDepList, peerDepList } = depsToUpdate; const dependencies = constructDeps(json, "dependencies", depList); const devDependencies = constructDeps(json, "devDependencies", devDepList); const peerDependencies = constructDeps(json, "peerDependencies", peerDepList); if (isDebugging) { logger({ type: "debug", section: "constructJson", isDebugging }); console.debug({ dependencies, devDependencies, peerDependencies }); } return { ...json, ...dependencies ? { dependencies } : {}, ...devDependencies ? { devDependencies } : {}, ...peerDependencies ? { peerDependencies } : {} }; }; var checkDependenciesForVersion = (versionMap, json, options) => { const { name, dependencies, devDependencies, peerDependencies } = json; const { isUpdating, isDebugging, isSilent, isTesting } = options; if (!dependencies && !devDependencies && !peerDependencies) return false; const depList = constructDepsToUpdateList(dependencies, versionMap); const devDepList = constructDepsToUpdateList(devDependencies, versionMap); const peerDepList = constructDepsToUpdateList(peerDependencies, versionMap); if (isDebugging) { logger({ type: "debug", isDebugging, section: "checkDependenciesForVersion" }); console.debug({ depList, devDepList, peerDepList }); } if (!depList.length && !devDepList.length && !peerDepList.length) { return false; } if (!isSilent) Array.from([depList, devDepList, peerDepList], (list) => writeConsoleMsgs(name, list)); if (isUpdating) { const updatedJson = constructJson(json, { depList, devDepList, peerDepList }, isDebugging); const { path, ...newJson } = updatedJson; if (!isTesting) { (0, import_fs.writeFileSync)(path, JSON.stringify(newJson, null, 2).concat("\n")); } else { logger({ type: "info", section: "checkDependenciesForVersion:test-writeFileSync:", message: path }); } } return true; }; var checkMatches = ({ versionMap, rootDir, files, isUpdating = false, isDebugging = false, isSilent = true, isCLI = false, isTesting = false }) => { const packagesNeedingUpdate = files.map((file) => { const path = `${rootDir}${file}`; const packageJson = (0, import_fs.readFileSync)(path, "utf8"); const json = JSON.parse(packageJson); return { ...json, path }; }).filter( (json) => checkDependenciesForVersion(versionMap, json, { isUpdating, isDebugging, isSilent, isTesting }) ); if (isDebugging) { logger({ type: "debug", section: "checkMatches", isDebugging, message: "see updates" }); console.debug({ packagesNeedingUpdate }); } const isOutOfDate = packagesNeedingUpdate.length > 0; if (isOutOfDate && !isUpdating) { logger({ type: "error", message: "Dependencies are not correct. \u{1F61E}" }); if (isCLI) process.exit(1); } else if (isOutOfDate) { logger({ type: "info", message: "Dependencies were not correct but should be updated! Check your git status. \u{1F603}" }); } else { logger({ type: "log", message: "No dependency issues found! \u{1F44C}" }); } }; var checkFiles = async ({ codependencies, files: matchers = ["package.json"], rootDir = "./", ignore = ["**/node_modules/**"], update = false, debug = false, silent = false, isCLI = false, yarnConfig = false, isTesting = false }) => { try { const files = glob(matchers, { cwd: rootDir, ignore }); if (!codependencies) throw '"codependencies" are required'; const versionMap = await constructVersionMap({ codependencies, debug, yarnConfig, isTesting }); checkMatches({ versionMap, rootDir, files, isCLI, isSilent: silent, isUpdating: update, isDebugging: debug, isTesting }); } catch (err) { if (debug) { logger({ type: "error", isDebugging: true, section: "checkFiles", message: err.toString() }); } } }; var script = checkFiles; // src/program.ts async function action(options = {}) { const explorer = (0, import_cosmiconfig.cosmiconfigSync)("codependence"); const result = options?.searchPath ? explorer.search(options.searchPath) : explorer.search(); const { config: pathConfig = {} } = options?.config ? explorer.load(options?.config) : {}; const updatedConfig = { ...!Object.keys(pathConfig).length ? result?.config : {}, ...pathConfig?.codependence ? { ...pathConfig.codependence } : pathConfig, ...options, isCLI: true }; const { config: usedConfig, searchPath: usedSearchPath, isTestingCLI, isTestingAction, ...updatedOptions } = updatedConfig; if (isTestingCLI) { console.info({ updatedOptions }); return; } if (isTestingAction) return updatedOptions; try { if (!updatedOptions.codependencies) throw '"codependencies" is required'; const spinner = (0, import_ora.default)(`\u{1F93C}\u200D\u2640\uFE0F ${import_gradient_string2.default.teen(`codependence`)} wrestling... `).start(); await script(updatedOptions); spinner.succeed(`\u{1F93C}\u200D\u2640\uFE0F ${import_gradient_string2.default.teen(`codependence`)} pinned!`); } catch (err) { logger({ type: "error", section: "cli:error", message: err.toString() }); } } import_commander.program.description( "Codependency, for code dependency. Checks `coDependencies` in package.json files to ensure dependencies are up-to-date" ).option("-t, --isTestingCLI", "enable CLI only testing").option("--isTesting", "enable running fn tests w/o overwriting").option("-f, --files [files...]", "file glob pattern").option("-u, --update", "update dependencies based on check").option("-r, --rootDir ", "root directory to start search").option("-i, --ignore [ignore...]", "ignore glob pattern").option("--debug", "enable debugging").option("--silent", "enable mainly silent logging").option("-cds, --codependencies [codependencies...]", "deps to check").option("-c, --config ", "path to a config file").option("-s, --searchPath ", "path to do a config file search").option("-y, --yarnConfig", "enable yarn config support").action(action).parse(process.argv); // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { script });