fyn
Version:
fyn is the NPM for fynpo -- a zero setup monorepo tool
1,805 lines (1,536 loc) • 3.69 MB
JavaScript
#!/usr/bin/env node
/******/ (() => { // webpackBootstrap
/******/ var __webpack_modules__ = ({
/***/ "./cli/config/npm-config.js":
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
// defaults, types, and shorthands.
// from npm
/* eslint-disable */
var path = __webpack_require__("path");
var url = __webpack_require__("url");
var Stream = (__webpack_require__("stream").Stream);
var semver = __webpack_require__("./node_modules/.f/_/semver/7.7.2/semver/index.js");
var stableFamily = semver.parse(process.version);
var nopt = __webpack_require__("./node_modules/.f/_/nopt/5.0.0/nopt/lib/nopt.js");
var os = __webpack_require__("os");
var osenv = __webpack_require__("./node_modules/.f/_/osenv/0.1.5/osenv/osenv.js");
var hasUnicode = __webpack_require__("./node_modules/.f/_/has-unicode/2.0.1/has-unicode/index.js");
var umask = __webpack_require__("./node_modules/.f/_/umask/1.1.0/umask/index.js");
var npmlog = __webpack_require__("./node_modules/.f/_/npmlog/4.1.2/npmlog/log.js");
var _fromString = umask.fromString; // fromString with logging callback
umask.fromString = function (val) {
_fromString(val, function (err, result) {
if (err) {
npmlog.warn("invalid umask", err.message);
}
val = result;
});
return val;
};
var log;
try {
log = __webpack_require__("./node_modules/.f/_/npmlog/4.1.2/npmlog/log.js");
} catch (er) {
var util = __webpack_require__("util");
log = {
warn: function (m) {
console.warn(m + " " + util.format.apply(util, [].slice.call(arguments, 1)));
}
};
}
exports.Umask = Umask;
function Umask() {}
function validateUmask(data, k, val) {
return umask.validate(data, k, val);
}
function validateSemver(data, k, val) {
if (!semver.valid(val)) return false;
data[k] = semver.valid(val);
}
function validateStream(data, k, val) {
if (!(val instanceof Stream)) return false;
data[k] = val;
}
nopt.typeDefs.semver = {
type: semver,
validate: validateSemver
};
nopt.typeDefs.Stream = {
type: Stream,
validate: validateStream
};
nopt.typeDefs.Umask = {
type: Umask,
validate: validateUmask
};
nopt.invalidHandler = function (k, val, type) {
log.warn("invalid config", k + "=" + JSON.stringify(val));
if (Array.isArray(type)) {
if (type.indexOf(url) !== -1) type = url;else if (type.indexOf(path) !== -1) type = path;
}
switch (type) {
case Umask:
log.warn("invalid config", "Must be umask, octal number in range 0000..0777");
break;
case url:
log.warn("invalid config", "Must be a full url with 'http://'");
break;
case path:
log.warn("invalid config", "Must be a valid filesystem path");
break;
case Number:
log.warn("invalid config", "Must be a numeric value");
break;
case Stream:
log.warn("invalid config", "Must be an instance of the Stream class");
break;
}
};
if (!stableFamily || +stableFamily.minor % 2) stableFamily = null;else stableFamily = stableFamily.major + "." + stableFamily.minor;
var defaults;
var temp = osenv.tmpdir();
var home = osenv.home();
var uidOrPid = process.getuid ? process.getuid() : process.pid;
if (home) process.env.HOME = home;else home = path.resolve(temp, "npm-" + uidOrPid);
var cacheExtra = process.platform === "win32" ? "npm-cache" : ".npm";
var cacheRoot = process.platform === "win32" && process.env.APPDATA || home;
var cache = path.resolve(cacheRoot, cacheExtra);
var globalPrefix;
Object.defineProperty(exports, "defaults", ({
get: function () {
if (defaults) return defaults;
if (process.env.PREFIX) {
globalPrefix = process.env.PREFIX;
} else if (process.platform === "win32") {
// c:\node\node.exe --> prefix=c:\node\
globalPrefix = path.dirname(process.execPath);
} else {
// /usr/local/bin/node --> prefix=/usr/local
globalPrefix = path.dirname(path.dirname(process.execPath)); // destdir only is respected on Unix
if (process.env.DESTDIR) {
globalPrefix = path.join(process.env.DESTDIR, globalPrefix);
}
}
defaults = {
access: null,
"allow-same-version": false,
"always-auth": false,
also: null,
audit: true,
"audit-level": "low",
"auth-type": "legacy",
"bin-links": true,
browser: null,
ca: null,
cafile: null,
cache: cache,
"cache-lock-stale": 60000,
"cache-lock-retries": 10,
"cache-lock-wait": 10000,
"cache-max": Infinity,
"cache-min": 10,
cert: null,
cidr: null,
color: process.env.NO_COLOR == null,
depth: Infinity,
description: true,
dev: false,
"dry-run": false,
editor: osenv.editor(),
"engine-strict": false,
force: false,
"fetch-retries": 2,
"fetch-retry-factor": 10,
"fetch-retry-mintimeout": 10000,
"fetch-retry-maxtimeout": 60000,
git: "git",
"git-tag-version": true,
"commit-hooks": true,
global: false,
globalconfig: path.resolve(globalPrefix, "etc", "npmrc"),
"global-style": false,
group: process.platform === "win32" ? 0 : process.env.SUDO_GID || process.getgid && process.getgid(),
"ham-it-up": false,
heading: "npm",
"if-present": false,
"ignore-prepublish": false,
"ignore-scripts": false,
"init-module": path.resolve(home, ".npm-init.js"),
"init-author-name": "",
"init-author-email": "",
"init-author-url": "",
"init-version": "1.0.0",
"init-license": "ISC",
json: false,
key: null,
"legacy-bundling": false,
link: false,
"local-address": undefined,
loglevel: "notice",
// logstream: process.stderr,
"logs-max": 10,
long: false,
maxsockets: 50,
message: "%s",
"metrics-registry": null,
"node-options": null,
"node-version": process.version,
offline: false,
"onload-script": false,
only: null,
optional: true,
otp: null,
"package-lock": true,
"package-lock-only": false,
parseable: false,
"prefer-offline": false,
"prefer-online": false,
prefix: globalPrefix,
preid: "",
// production: process.env.NODE_ENV === "production",
// progress: !process.env.TRAVIS && !process.env.CI,
proxy: null,
"https-proxy": null,
noproxy: null,
"user-agent": "npm/{npm-version} " + "node/{node-version} " + "{platform} " + "{arch}",
"read-only": false,
"rebuild-bundle": true,
registry: "https://registry.npmjs.org/",
rollback: true,
save: true,
"save-bundle": false,
"save-dev": false,
"save-exact": false,
"save-optional": false,
"save-prefix": "^",
"save-prod": false,
scope: "",
"script-shell": null,
"scripts-prepend-node-path": "warn-only",
searchopts: "",
searchexclude: null,
searchlimit: 20,
searchstaleness: 15 * 60,
"send-metrics": false,
shell: osenv.shell(),
shrinkwrap: true,
"sign-git-commit": false,
"sign-git-tag": false,
"sso-poll-frequency": 500,
"sso-type": "oauth",
"strict-ssl": true,
tag: "latest",
"tag-version-prefix": "v",
timing: false,
tmp: temp,
unicode: hasUnicode(),
"unsafe-perm": process.platform === "win32" || process.platform === "cygwin" || !(process.getuid && process.setuid && process.getgid && process.setgid) || process.getuid() !== 0,
"update-notifier": true,
usage: false,
user: process.platform === "win32" ? 0 : "nobody",
userconfig: path.resolve(home, ".npmrc"),
umask: process.umask ? process.umask() : umask.fromString("022"),
version: false,
versions: false,
viewer: process.platform === "win32" ? "browser" : "man",
_exit: true
};
return defaults;
}
}));
exports.types = {
access: [null, "restricted", "public"],
"allow-same-version": Boolean,
"always-auth": Boolean,
also: [null, "dev", "development"],
audit: Boolean,
"audit-level": ["low", "moderate", "high", "critical"],
"auth-type": ["legacy", "sso", "saml", "oauth"],
"bin-links": Boolean,
browser: [null, String],
ca: [null, String, Array],
cafile: path,
cache: path,
"cache-lock-stale": Number,
"cache-lock-retries": Number,
"cache-lock-wait": Number,
"cache-max": Number,
"cache-min": Number,
cert: [null, String],
cidr: [null, String, Array],
color: ["always", Boolean],
depth: Number,
description: Boolean,
dev: Boolean,
"dry-run": Boolean,
editor: String,
"engine-strict": Boolean,
force: Boolean,
"fetch-retries": Number,
"fetch-retry-factor": Number,
"fetch-retry-mintimeout": Number,
"fetch-retry-maxtimeout": Number,
git: String,
"git-tag-version": Boolean,
"commit-hooks": Boolean,
global: Boolean,
globalconfig: path,
"global-style": Boolean,
group: [Number, String],
"https-proxy": [null, url],
"user-agent": String,
"ham-it-up": Boolean,
heading: String,
"if-present": Boolean,
"ignore-prepublish": Boolean,
"ignore-scripts": Boolean,
"init-module": path,
"init-author-name": String,
"init-author-email": String,
"init-author-url": ["", url],
"init-license": String,
"init-version": semver,
json: Boolean,
key: [null, String],
"legacy-bundling": Boolean,
link: Boolean,
"local-address": getLocalAddresses(),
loglevel: ["silent", "error", "warn", "notice", "http", "timing", "info", "verbose", "silly"],
// logstream: Stream,
"logs-max": Number,
long: Boolean,
maxsockets: Number,
message: String,
"metrics-registry": [null, String],
"node-options": [null, String],
"node-version": [null, semver],
noproxy: [null, String, Array],
offline: Boolean,
"onload-script": [null, String],
only: [null, "dev", "development", "prod", "production"],
optional: Boolean,
"package-lock": Boolean,
otp: [null, String],
"package-lock-only": Boolean,
parseable: Boolean,
"prefer-offline": Boolean,
"prefer-online": Boolean,
prefix: path,
preid: String,
// production: Boolean,
progress: Boolean,
proxy: [null, false, url],
// allow proxy to be disabled explicitly
"read-only": Boolean,
"rebuild-bundle": Boolean,
registry: [null, url],
rollback: Boolean,
save: Boolean,
"save-bundle": Boolean,
"save-dev": Boolean,
"save-exact": Boolean,
"save-optional": Boolean,
"save-prefix": String,
"save-prod": Boolean,
scope: String,
"script-shell": [null, String],
"scripts-prepend-node-path": [false, true, "auto", "warn-only"],
searchopts: String,
searchexclude: [null, String],
searchlimit: Number,
searchstaleness: Number,
"send-metrics": Boolean,
shell: String,
shrinkwrap: Boolean,
"sign-git-commit": Boolean,
"sign-git-tag": Boolean,
"sso-poll-frequency": Number,
"sso-type": [null, "oauth", "saml"],
"strict-ssl": Boolean,
tag: String,
timing: Boolean,
tmp: path,
unicode: Boolean,
"unsafe-perm": Boolean,
"update-notifier": Boolean,
usage: Boolean,
user: [Number, String],
userconfig: path,
umask: Umask,
version: Boolean,
"tag-version-prefix": String,
versions: Boolean,
viewer: String,
_exit: Boolean
};
function getLocalAddresses() {
var interfaces; // #8094: some environments require elevated permissions to enumerate
// interfaces, and synchronously throw EPERM when run without
// elevated privileges
try {
interfaces = os.networkInterfaces();
} catch (e) {
interfaces = {};
}
return Object.keys(interfaces).map(nic => interfaces[nic].map(({
address
}) => address)).reduce((curr, next) => curr.concat(next), []).concat(undefined);
}
exports.shorthands = {
s: ["--loglevel", "silent"],
d: ["--loglevel", "info"],
dd: ["--loglevel", "verbose"],
ddd: ["--loglevel", "silly"],
noreg: ["--no-registry"],
N: ["--no-registry"],
reg: ["--registry"],
"no-reg": ["--no-registry"],
silent: ["--loglevel", "silent"],
verbose: ["--loglevel", "verbose"],
quiet: ["--loglevel", "warn"],
q: ["--loglevel", "warn"],
h: ["--usage"],
H: ["--usage"],
"?": ["--usage"],
help: ["--usage"],
v: ["--version"],
f: ["--force"],
desc: ["--description"],
"no-desc": ["--no-description"],
local: ["--no-global"],
l: ["--long"],
m: ["--message"],
p: ["--parseable"],
porcelain: ["--parseable"],
readonly: ["--read-only"],
g: ["--global"],
S: ["--save"],
D: ["--save-dev"],
E: ["--save-exact"],
O: ["--save-optional"],
P: ["--save-prod"],
y: ["--yes"],
n: ["--no-yes"],
B: ["--save-bundle"],
C: ["--prefix"]
};
/***/ }),
/***/ "./cli/default-rc.js":
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
"use strict";
const ci = __webpack_require__("./node_modules/.f/_/ci-info/2.0.0/ci-info/index.js");
module.exports = {
registry: "https://registry.npmjs.org",
targetDir: "node_modules",
progress: ci.isCI ? "none" : "normal"
};
/***/ }),
/***/ "./cli/fyn-cli.js":
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
"use strict";
// const Module = require("module");
const Fs = __webpack_require__("./lib/util/file-ops.js");
const Os = __webpack_require__("os");
const Path = __webpack_require__("path");
const Promise = __webpack_require__("./node_modules/.f/_/aveazul/1.0.2/aveazul/lib/aveazul.js");
const Fyn = __webpack_require__("./lib/fyn.js");
const _ = __webpack_require__("./node_modules/.f/_/lodash/4.17.21/lodash/lodash.min.js");
const PkgInstaller = __webpack_require__("./lib/pkg-installer.js"); // const DepData = require("../lib/dep-data");
const semver = __webpack_require__("./node_modules/.f/_/semver/7.7.2/semver/index.js");
const chalk = __webpack_require__("./node_modules/.f/_/chalk/4.1.2/chalk/source/index.js");
const logger = __webpack_require__("./lib/logger.js");
const PromiseQueue = __webpack_require__("./lib/util/promise-queue.js");
const sortObjKeys = __webpack_require__("./lib/util/sort-obj-keys.js");
const fyntil = __webpack_require__("./lib/util/fyntil.js");
const showStat = __webpack_require__("./cli/show-stat.js"); // const showSetupInfo = require("./show-setup-info");
// const logFormat = require("../lib/util/log-format");
const {
runNpmScript,
addNpmLifecycle
} = __webpack_require__("./lib/util/run-npm-script.js");
const npmLifecycle = __webpack_require__("./node_modules/.f/_/npm-lifecycle/3.1.5/npm-lifecycle/index.js");
const npmlog = __webpack_require__("./node_modules/.f/_/npmlog/4.1.2/npmlog/log.js");
const xaa = __webpack_require__("./lib/util/xaa.js");
const {
scanFileStats
} = __webpack_require__("./lib/util/stat-dir.js");
const {
checkPkgNewVersionEngine
} = __webpack_require__("./node_modules/.f/_/check-pkg-new-version-engine/1.0.3/check-pkg-new-version-engine/dist/index.js");
const fetch = __webpack_require__("./node_modules/.f/_/node-fetch-npm/2.0.4/node-fetch-npm/src/index.js");
const myPkg = __webpack_require__("./cli/mypkg.js");
const {
cleanErrorStack
} = __webpack_require__("./node_modules/.f/_/@jchip/error/1.0.3/@jchip/error/dist/index.js");
const {
setupNodeGypEnv
} = __webpack_require__("./lib/util/setup-node-gyp.js");
const hardLinkDir = __webpack_require__("./lib/util/hard-link-dir.js");
const xsh = __webpack_require__("./node_modules/.f/_/xsh/0.4.5/xsh/lib/index.js");
function checkNewVersion(npmConfig) {
checkPkgNewVersionEngine({
pkg: _.pick(myPkg, ["name", "version"]),
npmConfig,
checkIsNewer: (pkg, distTags, tag) => {
const isNewer = semver.gt(distTags[tag], pkg.version);
return {
isNewer,
version: distTags[tag]
};
},
fetchJSON: async (url, options) => {
const res = await fetch(url, options);
return await res.json();
}
});
}
const {
FETCH_META,
FETCH_PACKAGE,
LOAD_PACKAGE,
INSTALL_PACKAGE,
spinner
} = __webpack_require__("./lib/log-items.js");
const myDir = Path.join(__dirname, "..");
class FynCli {
constructor(config) {
this._config = config;
this._opts = config.opts;
if (config.noStartupInfo !== true) this.showStartupInfo();
this._fyn = undefined;
}
get fyn() {
if (!this._fyn) {
this._fyn = new Fyn(this._config);
}
return this._fyn;
}
showStartupInfo() {
logger.verbose(chalk.green("fyn"), "version", myPkg.version, "at", chalk.magenta(myDir));
logger.verbose(chalk.green("NodeJS"), "version", process.version, "at", chalk.magenta(process.execPath));
logger.verbose("env NODE_OPTIONS is", chalk.magenta(process.env.NODE_OPTIONS));
logger.verbose("working dir is", chalk.magenta(this._opts.cwd));
logger.verbose("Max network concurrency is", this._opts.concurrency);
}
async saveLogs(dbgLog) {
return Fs.writeFile(Path.resolve(this._opts.cwd, dbgLog), logger.logData.join("\n") + "\n");
}
async fail(msg, err) {
const dbgLog = this._opts.saveLogs || Path.join(Os.tmpdir(), `fyn-debug-${process.pid}-${Date.now()}.log`);
logger.freezeItems(true);
logger.error(msg, `CWD ${this.fyn.cwd}`);
logger.error("process.argv", process.argv);
logger.error(msg, "Please check for any errors that occur above.");
const lessCmd = chalk.magenta(`less -R ${dbgLog}`);
logger.error(msg, `Also check ${chalk.magenta(dbgLog)} for more details. ${lessCmd} if you are on Un*x.`);
if (err.stack) {
logger.error(msg, cleanErrorStack(err));
} else if (err.message) {
logger.error(msg, err.message);
}
await this.saveLogs(dbgLog);
fyntil.exit(err);
}
add(argv) {
return this.fyn._initialize().then(() => this._add(argv));
}
async _add(argv) {
const addSec = async (section, packages) => {
if (_.isEmpty(packages)) return [];
const items = await xaa.map(packages, async pkgSemver => {
const xfp = Path.resolve(pkgSemver);
const stat = await xaa.try(() => Fs.stat(xfp));
if (stat && stat.isDirectory()) {
pkgSemver = Path.relative(process.cwd(), xfp);
if (!pkgSemver.startsWith(`..${Path.sep}`)) {
pkgSemver = `.${Path.sep}${pkgSemver}`;
}
}
const posixPath = pkgSemver.replace(/\\/g, "/");
const semverPath = this.fyn.pkgSrcMgr.getSemverAsFilepath(posixPath);
logger.info("found semverPath", semverPath);
if (semverPath) {
return {
$: posixPath,
name: "",
semver: posixPath,
semverPath,
localType: "hard",
section,
parent: {}
};
}
const atX = posixPath.lastIndexOf("@");
return {
$: posixPath,
name: atX > 0 ? posixPath.substr(0, atX) : posixPath,
semver: atX > 0 ? posixPath.substr(atX + 1) : "latest",
section,
parent: {}
};
});
if (!_.isEmpty(items)) {
logger.info(`Adding packages to ${section}:`, packages.join(", "));
}
return items;
};
const sections = {
dependencies: "packages",
devDependencies: "dev",
optionalDependencies: "optional",
peerDependencies: "peer"
};
let items = [];
for (const section in sections) {
const argKey = sections[section];
items = items.concat(await addSec(section, argv[argKey]));
}
if (_.isEmpty(items)) {
logger.error("No packages to add");
fyntil.exit(1);
}
logger.addItem({
name: FETCH_META,
color: "green",
spinner
});
logger.updateItem(FETCH_META, "loading meta...");
const results = [];
return new PromiseQueue({
concurrency: 10,
stopOnError: true,
processItem: item => {
let found;
return xaa.wrap(() => this._fyn._pkgSrcMgr.fetchLocalItem(item)).then(meta => meta || this.fyn.pkgSrcMgr.fetchMeta(item)).then(meta => {
if (!meta) {
logger.error("Unable to retrieve meta for package", item.name);
return;
} // logger.info("adding", x.name, x.semver, meta);
// look at dist tags
const tags = meta["dist-tags"];
if (meta.local) {
logger.info("adding local package at", item.fullPath);
item.name = meta.name;
item.version = _.get(meta, "json.version");
found = Path.relative(this.fyn.cwd, item.fullPath).replace(/\\/g, "/");
if (found !== item.fullPath && !found.startsWith(".")) {
found = `./${found}`;
}
} else if (tags && tags[item.semver]) {
logger.debug("adding with dist tag for", item.name, item.semver, tags[item.semver]);
found = `^${tags[item.semver]}`;
if (!semver.validRange(found)) found = tags[item.semver];
} else {
// search
const versions = Object.keys(meta.versions).filter(v => semver.satisfies(v, item.semver));
if (versions.length > 0) {
found = item.semver;
} else {
logger.error(chalk.red(`no matching version found for ${item.$}`));
}
}
if (found) {
logger.info(`found ${found} for ${item.$}`);
item.found = found;
results.push(item);
}
});
},
watchTime: 5000
}).addItems(items).resume().wait().then(async () => {
logger.removeItem(FETCH_META);
if (results.length === 0) {
logger.info("No packages found for add");
return false;
}
const added = _.mapValues(sections, () => []);
const pkg = this.fyn._pkg;
const pkgFyn = argv.pkgFyn ? (await this.fyn.loadPkgFyn()) || {} : pkg;
results.forEach(item => {
if (item.semverPath) {
// set in package-fyn
if (!this._fyn.isFynpo || !this._fyn._fynpo.graph.getPackageByName(item.name)) {
_.set(pkgFyn, ["fyn", item.section, item.name], item.found);
} // set in package if it's not there
if (!_.get(pkg, [item.section, item.name])) {
_.set(pkg, [item.section, item.name], item.version ? `^${item.version}` : item.found);
}
} else {
_.set(pkg, [item.section, item.name], item.found);
}
added[item.section].push(item.name);
});
Object.keys(sections).forEach(sec => {
if (added[sec].length > 0 && pkg[sec]) {
pkg[sec] = sortObjKeys(pkg[sec]);
if (_.get(pkgFyn, ["fyn", sec])) {
pkgFyn.fyn[sec] = sortObjKeys(pkgFyn.fyn[sec]);
}
logger.info(`Packages added to ${sec}:`, added[sec].join(", "));
}
});
await this.fyn.savePkg();
if (argv.pkgFyn) {
await this.fyn.savePkgFyn(pkgFyn);
}
return true;
});
}
async remove(argv) {
await this.fyn._initialize();
return this._remove(argv);
}
_remove(argv) {
if (_.isEmpty(argv.packages)) {
logger.error("No packages to remove");
fyntil.exit(1);
}
const sections = ["dependencies", "devDependencies", "optionalDependencies", "peerDependencies"];
const packages = argv.packages.slice();
const removed = [];
const removeFromSection = sec => {
const section = _.get(this.fyn._pkg, sec);
const fynSection = _.get(this.fyn._pkg, ["fyn", sec], {});
if (_.isEmpty(section) && _.isEmpty(fynSection)) return;
for (let i = 0; i < packages.length; i++) {
const pkgName = packages[i];
let found = false;
if (fynSection.hasOwnProperty(pkgName)) {
delete fynSection[pkgName];
found = true;
}
if (section.hasOwnProperty(pkgName)) {
delete section[pkgName];
found = true;
}
if (found) {
removed.push(pkgName);
packages[i] = undefined;
}
}
if (_.isEmpty(section)) {
_.unset(this.fyn._pkg, sec);
}
if (_.isEmpty(fynSection)) {
_.unset(this.fyn._pkg, ["fyn", sec]);
}
};
sections.forEach(removeFromSection);
const remaining = packages.filter(x => x);
if (!_.isEmpty(remaining)) {
logger.error("These packages don't exist in your package.json:", remaining.join(", "));
}
if (_.isEmpty(this.fyn._pkg.fyn)) {
_.unset(this.fyn._pkg, "fyn");
}
if (removed.length > 0) {
logger.info("removed packages from package.json:", removed.join(", "));
this.fyn.savePkg();
return true;
}
logger.error("No package was removed");
return false;
}
async syncLocalLinks() {
await this.fyn._initializePkg();
const {
localPkgLinks
} = this.fyn._installConfig;
if (!_.isEmpty(localPkgLinks)) {
for (const vdir in localPkgLinks) {
const tgtDir = Path.join(this.fyn._cwd, vdir);
const srcDir = Path.join(this.fyn._cwd, localPkgLinks[vdir].srcDir);
await hardLinkDir.link(srcDir, tgtDir, {
sourceMaps: localPkgLinks[vdir].sourceMaps
});
}
logger.info(`refreshed linked files for local packages`);
} else {
logger.info(`There are no local packages`);
}
}
/*
* npm scripts execution order on install
* 1. preinstall
* 1b. install node_modules
* 2. install
* 3. postinstall
* 4. prepare
*/
install() {
let failure;
let installLocked;
const start = Date.now();
return Promise.try(() => this.fyn._initializePkg()).then(async () => {
checkNewVersion(this.fyn._options);
if (!this.fyn._changeProdMode && !this.fyn._options.forceInstall && this.fyn._installConfig.time) {
const stats = await scanFileStats(this.fyn.cwd);
const {
latestMtimeMs
} = stats;
logger.debug("time check from install config - last install time", this.fyn._installConfig.time, "latest file time", latestMtimeMs);
logger.debug("stats", JSON.stringify(stats, null, 2));
if (latestMtimeMs < this.fyn._installConfig.time && !(await this.fyn.checkLocalPkgFromInstallConfigNeedInstall()) && // if fyn-lock.yaml has been removed, then run install also
this.fyn.checkFynLockExist()) {
throw new Error("No Change");
}
}
installLocked = await this.fyn.createInstallLock();
await this.fyn.readLockFiles();
await this.fyn._startInstall();
const pkg = this.fyn._pkg;
const preinstall = _.get(pkg, "scripts.preinstall");
if (preinstall) {
logger.addItem({
name: INSTALL_PACKAGE,
color: "green",
spinner
});
return runNpmScript({
appDir: this.fyn.cwd,
scripts: ["preinstall"],
fyn: this.fyn,
depInfo: {
name: pkg.name,
version: pkg.version,
dir: this.fyn.cwd
}
}).then(() => {
logger.removeItem(INSTALL_PACKAGE);
});
}
}).then(() => {
logger.addItem({
name: FETCH_META,
color: "green",
spinner
});
logger.updateItem(FETCH_META, "resolving dependencies...");
return this.fyn.resolveDependencies();
}).then(() => {
logger.removeItem(FETCH_META);
logger.addItem({
name: FETCH_PACKAGE,
color: "green",
spinner
});
logger.updateItem(FETCH_PACKAGE, "fetching packages...");
logger.addItem({
name: LOAD_PACKAGE,
color: "green",
spinner
});
logger.updateItem(LOAD_PACKAGE, "loading packages...");
return this.fyn.fetchPackages();
}).then(() => {
logger.removeItem(FETCH_PACKAGE);
logger.removeItem(LOAD_PACKAGE);
logger.addItem({
name: INSTALL_PACKAGE,
color: "green",
spinner
});
logger.updateItem(INSTALL_PACKAGE, "installing packages...");
const installer = new PkgInstaller({
fyn: this.fyn
});
return installer.install();
}).then(async () => {
const pkg = this.fyn._pkg;
const pkgScripts = pkg.scripts || {};
const npmInstallScripts = ["install", "postinstall", "prepare"]; // https://docs.npmjs.com/cli/v6/using-npm/scripts#npm-install
// Intentionally skipping the deprecated prepublish
const scripts = npmInstallScripts.filter(x => pkgScripts[x] !== undefined);
if (scripts.length > 0) {
await runNpmScript({
appDir: this.fyn.cwd,
scripts,
fyn: this.fyn,
depInfo: {
name: pkg.name,
version: pkg.version,
dir: this.fyn.cwd
}
});
} // run npm scripts from fynpo, with lifecycle scripts added
const _runNpm = this.fyn._runNpm.map(s => Array.isArray(s) ? s.find(s1 => pkgScripts[s1] !== undefined) : s);
const fynpoNpmScripts = addNpmLifecycle(_.without(_runNpm, ...npmInstallScripts), pkgScripts);
if (fynpoNpmScripts.length > 0) {
await runNpmScript({
appDir: this.fyn.cwd,
scripts: fynpoNpmScripts,
fyn: this.fyn,
depInfo: {
name: pkg.name,
version: pkg.version,
dir: this.fyn.cwd
}
});
}
}).then(async () => {
logger.removeItem(INSTALL_PACKAGE);
const end = Date.now();
await this.fyn.saveFynpoIndirects();
logger.info(chalk.green("complete in total"), chalk.magenta(`${(end - start) / 1000}`) + "secs");
}).catch(err => {
if (err.message === "No Change") {
logger.info(`No changes detected since last fyn install - nothing to be done.
To force install, run 'fyn install --force-install' or 'fyn install --fi'`);
} else {
failure = err;
}
}).finally(async () => {
if (installLocked === true) {
await this.fyn.removeInstallLock();
}
if (failure) {
await this.fail(chalk.red("install failed:"), failure);
return failure;
}
if (this._opts.saveLogs) {
await this.saveLogs(this._opts.saveLogs);
}
await this.fyn.saveInstallConfig();
fyntil.exit(0);
});
}
stat(argv) {
return showStat(this.fyn, argv.args.packages).finally(() => {
return this._opts.saveLogs && this.saveLogs(this._opts.saveLogs);
});
}
async runScript(pkg, script, env) {
const config = x => this.fyn.allrc[x];
const options = {
config: this.fyn.allrc,
dir: Path.join(this.fyn.cwd, this.fyn.targetDir),
failOk: false,
force: config("force"),
group: config("group"),
log: npmlog,
ignorePrepublish: config("ignore-prepublish"),
ignoreScripts: config("ignore-scripts"),
nodeOptions: config("node-options"),
production: this.fyn.production,
scriptShell: config("script-shell"),
scriptsPrependNodePath: config("scripts-prepend-node-path"),
unsafePerm: config("unsafe-perm"),
user: config("user"),
env
};
return npmLifecycle(pkg, script, this.fyn.cwd, options);
}
async runScripts(scripts, {
single
} = {}) {
if (!this.fyn._pkg) {
await this.fyn.loadPkg();
}
const pkg = Object.assign({}, this.fyn._pkg);
pkg._id = `${pkg.name}@${pkg.version}`;
const _scripts = [].concat(...scripts.map(s => {
if (!single && !s.startsWith("pre") && !s.startsWith("post")) {
return [`pre${s}`, s, `post${s}`];
} else {
return s;
}
}));
const env = npmLifecycle.initEnv(process.env, this.fyn.production); // add fynpo top dir node_modules/.bin to PATH
if (this._config._fynpo.config) {
xsh.envPath.addToFront(Path.join(this._config._fynpo.dir, "node_modules/.bin"), env);
}
setupNodeGypEnv(env);
return Promise.each(_scripts, s => _.get(pkg, ["scripts", s]) && this.runScript(pkg, s, Object.assign({}, env)));
}
async run(argv, script = "") {
if (!this._config._fynpo) {
this._config._fynpo = {};
}
script = script || argv.args.script;
if (argv.opts.list || !script) {
try {
await this.fyn.loadPkg();
if (!argv.opts.list) {
console.log(`Lifecycle scripts included in ${this.fyn._pkg.name}:\n`);
}
console.log(Object.keys(_.get(this.fyn._pkg, "scripts", {})).join("\n"));
} finally {
fyntil.exit(0);
}
}
await this.fyn.loadPkg();
if (!_.get(this.fyn._pkg, ["scripts", script])) {
logger.error(`Error: missing script: ${JSON.stringify(script)} - not found in package.json scripts`);
fyntil.exit(1);
}
return this.runScripts([script]);
}
}
module.exports = FynCli;
/***/ }),
/***/ "./cli/load-rc.js":
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
"use strict";
const os = __webpack_require__("os");
const Fs = __webpack_require__("fs");
const Path = __webpack_require__("path");
const Yaml = __webpack_require__("./node_modules/.f/_/yamljs/0.3.0/yamljs/lib/Yaml.js");
const Ini = __webpack_require__("./node_modules/.f/_/ini/2.0.0/ini/ini.js");
const _ = __webpack_require__("./node_modules/.f/_/lodash/4.17.21/lodash/lodash.min.js");
const logger = __webpack_require__("./lib/logger.js");
const assert = __webpack_require__("assert");
const defaultRc = __webpack_require__("./cli/default-rc.js");
const npmConfig = __webpack_require__("./cli/config/npm-config.js");
const fynTil = __webpack_require__("./lib/util/fyntil.js"); // replace any ${ENV} values with the appropriate environ.
// copied from https://github.com/npm/config/blob/1f47a6c6ae7864b412d45c6a4a74930cf3365395/lib/env-replace.js
const envExpr = /(?<!\\)(\\*)\$\{([^${}]+)\}/g;
function replaceEnv(f, env) {
return f.replace(envExpr, (orig, esc, name) => {
const val = env[name] !== undefined ? env[name] : `$\{${name}}`; // consume the escape chars that are relevant.
if (esc.length % 2) {
return orig.slice((esc.length + 1) / 2);
}
return esc.slice(esc.length / 2) + val;
});
}
function replaceRcEnv(rc, env) {
for (const k in rc) {
if (rc[k] && rc[k].replace) {
rc[k] = replaceEnv(rc[k], env);
}
}
}
function readRc(fname) {
const rcFname = Path.basename(fname);
try {
const rcData = Fs.readFileSync(fname).toString();
let rc;
try {
assert(rcFname === ".fynrc" && rcData.startsWith("---"));
rc = Yaml.parse(rcData);
logger.debug(`Loaded ${rcFname} YAML RC`, fname, JSON.stringify(fynTil.removeAuthInfo(rc)));
} catch (e) {
rc = Ini.parse(rcData);
logger.debug(`Loaded ${rcFname} ini RC`, fname, JSON.stringify(fynTil.removeAuthInfo(rc)));
}
return rc;
} catch (e) {
if (e.code !== "ENOENT") {
logger.error(`Failed to process ${rcFname} RC file`, fname, e.message);
}
return {};
}
}
function loadRc(cwd, fynpoDir) {
const npmrcData = [];
if (cwd === false) {
return {
npmrc: {}
};
}
const homeDir = os.homedir();
const files = [process.env.NPM_CONFIG_GLOBALCONFIG, Path.join(process.env.PREFIX || "", "/etc/npmrc"), process.env.NPM_CONFIG_USERCONFIG, Path.join(homeDir, ".npmrc"), Path.join(homeDir, ".fynrc"), // fynpo dir
fynpoDir && fynpoDir !== cwd && Path.join(fynpoDir, ".npmrc"), fynpoDir && fynpoDir !== cwd && Path.join(fynpoDir, ".fynrc"), Path.join(cwd, ".npmrc"), Path.join(cwd, ".fynrc")].filter(x => x);
const data = files.map(fp => {
const x = readRc(fp);
if (fp.endsWith("npmrc")) {
npmrcData.push(x);
}
return x;
});
const all = _.merge.apply(_, [{}, npmConfig.defaults, defaultRc].concat(data));
const npmrc = _.merge.apply(_, [{}, npmConfig.defaults].concat(npmrcData));
replaceRcEnv(all, process.env);
replaceRcEnv(npmrc, process.env);
return {
all,
npmrc,
data,
npmrcData,
files
};
}
module.exports = loadRc;
/***/ }),
/***/ "./cli/main.js":
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
"use strict";
const Path = __webpack_require__("path");
const chalk = __webpack_require__("./node_modules/.f/_/chalk/4.1.2/chalk/source/index.js");
const Promise = __webpack_require__("./node_modules/.f/_/aveazul/1.0.2/aveazul/lib/aveazul.js");
const FynCli = __webpack_require__("./cli/fyn-cli.js");
const _ = __webpack_require__("./node_modules/.f/_/lodash/4.17.21/lodash/lodash.min.js");
const CliLogger = __webpack_require__("./lib/cli-logger.js");
const logger = __webpack_require__("./lib/logger.js");
const NixClap = __webpack_require__("./node_modules/.f/_/nix-clap/1.3.13/nix-clap/lib/nix-clap.js");
const myPkg = __webpack_require__("./cli/mypkg.js");
const loadRc = __webpack_require__("./cli/load-rc.js");
const defaultRc = __webpack_require__("./cli/default-rc.js");
const fynTil = __webpack_require__("./lib/util/fyntil.js");
const {
runInitPackage
} = __webpack_require__("./node_modules/.f/_/init-package/1.0.0-fynlocal_h/init-package/dist/index.js");
function setLogLevel(ll) {
if (ll) {
const levels = Object.keys(CliLogger.Levels);
const real = _.find(levels, l => l.startsWith(ll));
const x = CliLogger.Levels[real];
if (x !== undefined) {
logger._logLevel = x;
} else {
logger.error(`Invalid log level "${ll}". Supported levels are: ${levels.join(", ")}`);
fynTil.exit(1);
}
}
}
const pickEnvOptions = () => {
const mapping = {
NODE_ENV: {
optKey: "production",
checkValue: "production"
}
};
return Object.keys(mapping).reduce((cfg, envKey) => {
if (process.env.hasOwnProperty(envKey)) {
const m = mapping[envKey];
const ev = process.env[envKey];
cfg[m.optKey] = ev === m.checkValue;
logger.info(`setting option ${m.optKey} to ${cfg[m.optKey]} by env ${envKey} value ${ev}`);
}
}, {});
};
const pickOptions = async (argv, nixClap, checkFynpo = true) => {
setLogLevel(argv.opts.logLevel);
chalk.enabled = argv.opts.colors;
let cwd = argv.opts.cwd || process.cwd();
if (!Path.isAbsolute(cwd)) {
cwd = Path.join(process.cwd(), cwd);
}
let fynpo = {};
if (checkFynpo) {
try {
fynpo = await fynTil.loadFynpo(cwd);
} catch (err) {
logger.error(err.stack);
process.exit(1);
}
}
const rcData = loadRc(argv.opts.rcfile && cwd, fynpo.dir);
const rc = rcData.all || defaultRc;
_.defaults(argv.opts, rc);
nixClap.applyConfig(pickEnvOptions(), argv);
argv.opts.cwd = cwd;
chalk.enabled = argv.opts.colors;
if (!argv.source.saveLogs.startsWith("cli")) {
argv.opts.saveLogs = undefined;
}
nixClap.applyConfig(_.get(fynpo, "config.fyn.options", {}), argv);
logger.debug("Final RC", JSON.stringify(fynTil.removeAuthInfo(argv.opts)));
setLogLevel(argv.opts.logLevel);
if (argv.opts.progress) logger.setItemType(argv.opts.progress);
return {
opts: argv.opts,
rcData,
_cliSource: argv.source,
_fynpo: fynpo
};
};
const options = {
fynlocal: {
type: "boolean",
desc: "enable/disable fynlocal mode",
default: true
},
"always-fetch-dist": {
type: "boolean",
desc: "fetch package dist tarball during dep resolving",
default: false
},
"central-store": {
type: "boolean",
alias: ["central", "cs"],
desc: "keep single copy of packages in central store",
default: false
},
copy: {
type: "string array",
alias: "cp",
desc: "copy package even in central store mode"
},
"log-level": {
alias: "q",
type: "string",
desc: "One of: debug,verbose,info,warn,error,fyi,none",
default: "info"
},
"save-logs": {
type: "string",
alias: "sl",
default: "fyn-debug.log",
desc: "Save all logs to the specified file"
},
colors: {
type: "boolean",
default: true,
desc: "Log with colors (--no-colors turn off)"
},
progress: {
type: "enum",
alias: "pg",
requireArg: true,
default: "normal",
enum: /^(normal|simple|none)$/,
desc: "Log progress type: normal,simple,none"
},
cwd: {
type: "string",
requireArg: true,
desc: "Change current working dir"
},
"fyn-dir": {
type: "string",
desc: "Dir for cache etc, default {HOME}/.fyn"
},
"force-cache": {
alias: "f",
type: "boolean",
desc: "Don't check registry if cache exists."
},
offline: {
type: "boolean",
desc: "Only lockfile or local cache. Fail if miss."
},
"lock-only": {
alias: "k",
type: "boolean",
desc: "Only resolve with lockfile. Fail if needs changes."
},
"prefer-lock": {
type: "boolean",
desc: "Prefer resolving with lockfile."
},
lockfile: {
type: "boolean",
alias: "lf",
default: true,
desc: "Support lockfile"
},
"lock-time": {
type: "string",
desc: "Lock dependencies by time"
},
"npm-lock": {
type: "boolean",
desc: "force on/off loading npm lock"
},
"refresh-optionals": {
type: "boolean",
default: false,
desc: "refresh all optionalDependencies"
},
"refresh-meta": {
type: "boolean",
default: false,
desc: "force refresh package meta from registry"
},
"ignore-dist": {
alias: "i",
type: "boolean",
desc: "Ignore host in tarball URL from meta dist."
},
"show-deprecated": {
alias: "s",
type: "boolean",
desc: "Force show deprecated messages"
},
"deep-resolve": {
alias: "dr",
type: "boolean",
desc: "Resolve dependency tree as deep as possible"
},
"source-maps": {
alias: "sm",
type: "boolean",
default: false,
desc: "Generate pseudo source maps for local linked packages"
},
production: {
type: "boolean",
alias: "prod",
default: false,
desc: "Ignore devDependencies" // allowCmd: ["add", "remove", "install"]
},
rcfile: {
type: "boolean",
default: true,
desc: "Load .fynrc and .npmrc files"
},
registry: {
type: "string",
alias: "reg",
requireArg: true,
desc: "Override registry url"
},
concurrency: {
type: "number",
alias: "cc",
desc: "Max network concurrency",
default: 15
},
"build-local": {
type: "boolean",
default: true,
desc: "auto run fyn to install and build local dependency packages"
},
"flatten-top": {
type: "boolean",
default: true,
desc: "flattening hoists pkg to top level node_modules"
},
layout: {
type: "enum",
default: "normal",
// node_modules package directory layouts
// normal - top level and hoist deps are all copied node_modules
// detail - every packages in their own path with version detail and symlink to node_modules
// TODO: simple - where top level deps are copied, but promoted packages are hoisted with symlinks
enum: /^(normal|detail)$/,
desc: "set node_modules packages layout - normal or detail"
},
"meta-memoize": {
type: "string",
alias: "meta-mem",
desc: "a url to a server that helps multiple fyn to share meta cache"
}
};
const commands = {
install: {
alias: "i",
desc: "Install modules",
async exec(argv, parsed) {
const cli = new FynCli(await pickOptions(argv, parsed.nixClap));
return cli.install();
},
default: true,
options: {
"run-npm": {
desc: "additional npm scripts to run after install",
type: "string array"
},
"force-install": {
alias: "fi",
desc: "force install even if no files changed since last install",
type: "boolean"
}
}
},
add: {
alias: "a",
args: "[packages..]",
usage: "$0 $1 [packages..] [--dev <dev packages>]",
desc: "add packages to package.json",
exec: async (argv, parsed) => {
const config = await pickOptions(argv, parsed.nixClap);
const lockFile = config.lockfile;
config.lockfile = false;
const cli = new FynCli(config);
const opts = Object.assign({}, argv.opts, argv.args);
return cli.add(opts).then(added => {
if (!added || !argv.opts.install) return;
config.lockfile = lockFile;
config.noStartupInfo = true;
logger.info("installing...");
fynTil.resetFynpo();
return new FynCli(config).install();
});
},
options: {
dev: {
alias: ["d"],
type: "array",
desc: "List of packages to add to devDependencies"
},
opt: {
type: "array",
desc: "List of packages to add to optionalDependencies"
},
peer: {
alias: ["p"],
type: "array",
desc: "List of packages to add to peerDependencies"
},
install: {
type: "boolean",
default: true,
desc: "Run install after added"
},
"pkg-fyn": {
type: "boolean",
desc: "save fyn section to package-fyn.json",
default: false
}
}
},
remove: {
alias: "rm",
args: "<packages..>",
desc: "Remove packages from package.json and install",
exec: async (argv, parsed) => {
const options = await pickOptions(argv, parsed.nixClap);
const lockFile = options.lockfile;
options.lockfile = false;
const cli = new FynCli(options);
const opts = Object.assign({}, argv.opts, argv.args);
const removed = await cli.remove(opts);
if (removed) {
if (!argv.opts.install) return;
options.lockfile = lockFile;
options.noStartupInfo = true;
fynTil.resetFynpo();
logger.info("installing...");
return await new FynCli(options).install();
}
},
options: {
install: {
type: "boolean",
default: true,
desc: "Run install after removed"
}
}
},
stat: {
desc: "Show stats of installed packages",
usage: "$0 $1 <package-name>[@semver] [...]",
args: "<string packages..>",
exec: async (argv, parsed) => {
return new FynCli(await pickOptions(argv, parsed.nixClap)).stat(argv);
}
},
run: {
desc: "Run a npm script",
args: "[script]",
alias: ["rum", "r"],
usage: "$0 $1 <command> [-- <args>...]",
exec: async (argv, parsed) => {
try {
const options = await pickOptions(argv, parsed.nixClap, !argv.opts.list);
return await new FynCli(options).run(argv);
} catch (err) {
if (err.errno !== undefined) {
process.exit(err.errno);
} else {
logger.error("fyn run caught error without errno", err);
process.exit(1);
}
}
},
options: {
list: {
desc: "list scripts",
alias: "l",
type: "boolean"
}
}
},
init: {
desc: "initialize a package.json file",
usage: "$0 $1 <command> [--yes]",
exec: async argv => {
try {
await runInitPackage(argv.opts.yes);
} catch (err) {
process.exit(1);
}
},
options: {
yes: {
alias: ["y"],
desc: "skip prompt and use default values",
type: "boolean"
}
}
},
"sync-local": {
desc: "Refresh locally linked package files",
alias: "sl",
async exec(argv, parsed) {
try {
const opts = await pickOptions(argv, parsed.nixClap, true);
const cli = new FynCli(opts);
return cli.syncLocalLinks();
} catch (err) {
process.exit(1);
}
}
}
};
const createNixClap = handlers => {
return new NixClap({
Promise,
name: myPkg.name,
version: myPkg.version,
usage: "$0 [options] <command>",
handlers
});
};
const run = async (args, start, tryRun = true) => {
fynTil.resetFynpo();
const handlers = {
"parse-fail": parsed => {
if (parsed.commands.length < 1 && parsed.error.message.includes("Unknown command")) {
parsed.nixClap.skipExec();
} else {
parsed.nixClap.showHelp(parsed.error);
}
},
"unknown-option": () => {}
};
if (start === undefined && args !== undefined) {
start = 0;
}
const parsed = await createNixClap(handlers).init(options, commands).parseAsync(args, start);
if (!tryRun || !parsed.error) {
return;
}
if (parsed.error && parsed.commands.length < 1) {
const x = start === undefined ? 2 : start;
const args2 = (args || process.argv).slice();
args2.splice(x, 0, "run");
await createNixClap().init(options, commands).parseAsync(args2, x);
} else {
parsed.nixClap.showHelp(parsed.error);
}
};
const fun = () => {
const argv = process.argv.slice();
argv.splice(2, 0, "run");
return run(argv, 2, false);
};
const nodeGyp = () => {
__webpack_require__("./node_modules/.f/_/node-gyp/8.4.1/node-gyp/bin/node-gyp.js");
};
const hardLinkDir = __webpack_require__("./lib/util/hard-link-dir.js");
module.exports = {
run,
fun,
nodeGyp,
hardLinkDir
};
/***/ }),
/***/ "./cli/mypkg.js":
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
"use strict";
/*
* Avoid webpack bundling the whole package.json if doing require("../package.json")
*/
const Fs = __webpack_require__("fs");
const Path = __webpack_require__("path");
const myPkg = JSON.parse(Fs.readFileSync(Path.join(__dirname, "../package.json")));
module.exports = myPkg;
/***/ }),
/***/ "./cli/show-stat.js":
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
"use strict";
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else