fyn 2.1.3 → 2.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +161 -0
- package/dist/fyn.js +1042 -156
- package/package.json +1 -1
package/dist/fyn.js
CHANGED
|
@@ -143,6 +143,7 @@ const myPkg = __webpack_require__("./cli/mypkg.ts");
|
|
|
143
143
|
const { cleanErrorStack } = __webpack_require__("./node_modules/.f/_/@jchip/error/1.0.3/@jchip/error/dist/index.js");
|
|
144
144
|
const { setupNodeGypEnv } = __webpack_require__("./lib/util/setup-node-gyp.ts");
|
|
145
145
|
const hardLinkDir = __webpack_require__("./lib/util/hard-link-dir.ts");
|
|
146
|
+
const { syncLocalExports, localExportsScanIgnores } = __webpack_require__("./lib/local-exports.ts");
|
|
146
147
|
const xsh = __webpack_require__("./node_modules/.f/_/xsh/0.4.6/xsh/lib/index.js");
|
|
147
148
|
function checkNewVersion(npmConfig) {
|
|
148
149
|
checkPkgNewVersionEngine({
|
|
@@ -417,13 +418,21 @@ class FynCli {
|
|
|
417
418
|
}
|
|
418
419
|
async syncLocalLinks() {
|
|
419
420
|
await this.fyn._initializePkg();
|
|
420
|
-
const { localPkgLinks } = this.fyn._installConfig;
|
|
421
|
+
const { localPkgLinks, localExports } = this.fyn._installConfig;
|
|
422
|
+
let refreshed = false;
|
|
421
423
|
if (!_.isEmpty(localPkgLinks)) {
|
|
422
424
|
for (const vdir in localPkgLinks) {
|
|
423
425
|
const tgtDir = Path.join(this.fyn._cwd, vdir);
|
|
424
426
|
const srcDir = Path.join(this.fyn._cwd, localPkgLinks[vdir].srcDir);
|
|
425
427
|
await hardLinkDir.link(srcDir, tgtDir, { sourceMaps: localPkgLinks[vdir].sourceMaps });
|
|
426
428
|
}
|
|
429
|
+
refreshed = true;
|
|
430
|
+
}
|
|
431
|
+
if (localExports) {
|
|
432
|
+
await syncLocalExports({ cwd: this.fyn._cwd, manifest: localExports });
|
|
433
|
+
refreshed = true;
|
|
434
|
+
}
|
|
435
|
+
if (refreshed) {
|
|
427
436
|
logger.info(`refreshed linked files for local packages`);
|
|
428
437
|
} else {
|
|
429
438
|
logger.info(`There are no local packages`);
|
|
@@ -444,7 +453,9 @@ class FynCli {
|
|
|
444
453
|
return Promise.try(() => this.fyn._initializePkg()).then(async () => {
|
|
445
454
|
checkNewVersion(this.fyn._options);
|
|
446
455
|
if (!this.fyn._changeProdMode && !this.fyn._options.forceInstall && this.fyn._installConfig.time) {
|
|
447
|
-
const stats = await scanFileStats(this.fyn.cwd
|
|
456
|
+
const stats = await scanFileStats(this.fyn.cwd, {
|
|
457
|
+
moreIgnores: localExportsScanIgnores(this.fyn._pkg)
|
|
458
|
+
});
|
|
448
459
|
const { latestMtimeMs } = stats;
|
|
449
460
|
logger.debug(
|
|
450
461
|
"time check from install config - last install time",
|
|
@@ -616,16 +627,13 @@ class FynCli {
|
|
|
616
627
|
}
|
|
617
628
|
script = script || argv.args?.script;
|
|
618
629
|
if (argv.opts?.list || !script) {
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
console.log(`Lifecycle scripts included in ${this.fyn._pkg.name}:
|
|
630
|
+
await this.fyn.loadPkg();
|
|
631
|
+
if (!argv.opts?.list) {
|
|
632
|
+
console.log(`Lifecycle scripts included in ${this.fyn._pkg.name}:
|
|
623
633
|
`);
|
|
624
|
-
}
|
|
625
|
-
console.log(Object.keys(_.get(this.fyn._pkg, "scripts", {})).join("\n"));
|
|
626
|
-
} finally {
|
|
627
|
-
fyntil.exit(0);
|
|
628
634
|
}
|
|
635
|
+
console.log(Object.keys(_.get(this.fyn._pkg, "scripts", {})).join("\n"));
|
|
636
|
+
fyntil.exit(0);
|
|
629
637
|
}
|
|
630
638
|
await this.fyn.loadPkg();
|
|
631
639
|
if (!_.get(this.fyn._pkg, ["scripts", script])) {
|
|
@@ -786,8 +794,15 @@ const pickEnvOptions = () => {
|
|
|
786
794
|
cfg[m.optKey] = ev === m.checkValue;
|
|
787
795
|
logger.info(`setting option ${m.optKey} to ${cfg[m.optKey]} by env ${envKey} value ${ev}`);
|
|
788
796
|
}
|
|
797
|
+
return cfg;
|
|
789
798
|
}, {});
|
|
790
799
|
};
|
|
800
|
+
const getRunExitCode = (err) => err.code !== void 0 ? err.code : err.errno || 1;
|
|
801
|
+
const setLockfile = (config, lockfile) => {
|
|
802
|
+
const previous = config.opts.lockfile;
|
|
803
|
+
config.opts.lockfile = lockfile;
|
|
804
|
+
return previous;
|
|
805
|
+
};
|
|
791
806
|
const pickOptions = async (cmd, checkFynpo = true) => {
|
|
792
807
|
const meta = cmd.jsonMeta;
|
|
793
808
|
const rootOpts = cmd.rootCmd?.opts || {};
|
|
@@ -830,6 +845,11 @@ const pickOptions = async (cmd, checkFynpo = true) => {
|
|
|
830
845
|
if (allOpts.progress) logger.setItemType(allOpts.progress);
|
|
831
846
|
return { opts: allOpts, rcData, _cliSource: meta.source, _fynpo: fynpo };
|
|
832
847
|
};
|
|
848
|
+
const makeFynGlobal = async (cmd, extra = {}) => {
|
|
849
|
+
const { opts } = await pickOptions(cmd, false);
|
|
850
|
+
const tag = cmd.getParent()?.opts?.tag;
|
|
851
|
+
return new FynGlobal({ globalDir: cmd.opts?.dir, tag, fynOpts: opts, ...extra });
|
|
852
|
+
};
|
|
833
853
|
const options = {
|
|
834
854
|
fynlocal: {
|
|
835
855
|
args: "<flag boolean>",
|
|
@@ -930,6 +950,10 @@ const options = {
|
|
|
930
950
|
args: "<flag boolean>",
|
|
931
951
|
desc: "Ignore host in tarball URL from meta dist."
|
|
932
952
|
},
|
|
953
|
+
"enforce-registry-deps": {
|
|
954
|
+
args: "<flag boolean>",
|
|
955
|
+
desc: "Require transitive deps to be from a registry (default on). --no-enforce-registry-deps to disable."
|
|
956
|
+
},
|
|
933
957
|
"show-deprecated": {
|
|
934
958
|
alias: "s",
|
|
935
959
|
args: "<flag boolean>",
|
|
@@ -1030,13 +1054,12 @@ const commands = {
|
|
|
1030
1054
|
Object.assign(meta.opts, cmd.rootCmd.opts);
|
|
1031
1055
|
}
|
|
1032
1056
|
const config = await pickOptions(cmd);
|
|
1033
|
-
const lockFile = config
|
|
1034
|
-
config.lockfile = false;
|
|
1057
|
+
const lockFile = setLockfile(config, false);
|
|
1035
1058
|
const cli = new FynCli(config);
|
|
1036
1059
|
const opts = Object.assign({}, meta.opts, meta.args);
|
|
1037
1060
|
return cli.add(opts).then((added) => {
|
|
1038
1061
|
if (!added || !meta.opts.install) return;
|
|
1039
|
-
config
|
|
1062
|
+
setLockfile(config, lockFile);
|
|
1040
1063
|
config.noStartupInfo = true;
|
|
1041
1064
|
logger.info("installing...");
|
|
1042
1065
|
fynTil.resetFynpo();
|
|
@@ -1080,14 +1103,13 @@ const commands = {
|
|
|
1080
1103
|
Object.assign(meta.opts, cmd.rootCmd.opts);
|
|
1081
1104
|
}
|
|
1082
1105
|
const options2 = await pickOptions(cmd);
|
|
1083
|
-
const lockFile = options2
|
|
1084
|
-
options2.lockfile = false;
|
|
1106
|
+
const lockFile = setLockfile(options2, false);
|
|
1085
1107
|
const cli = new FynCli(options2);
|
|
1086
1108
|
const opts = Object.assign({}, meta.opts, meta.args);
|
|
1087
1109
|
const removed = await cli.remove(opts);
|
|
1088
1110
|
if (removed) {
|
|
1089
1111
|
if (!meta.opts.install) return;
|
|
1090
|
-
options2
|
|
1112
|
+
setLockfile(options2, lockFile);
|
|
1091
1113
|
options2.noStartupInfo = true;
|
|
1092
1114
|
fynTil.resetFynpo();
|
|
1093
1115
|
logger.info("installing...");
|
|
@@ -1121,7 +1143,7 @@ const commands = {
|
|
|
1121
1143
|
const options2 = await pickOptions(cmd, !meta.opts.list);
|
|
1122
1144
|
return await new FynCli(options2).run(meta, void 0, cmd, parsed);
|
|
1123
1145
|
} catch (err) {
|
|
1124
|
-
const exitCode = err
|
|
1146
|
+
const exitCode = getRunExitCode(err);
|
|
1125
1147
|
if (err.event && err.script) {
|
|
1126
1148
|
logger.error(chalk.red(`Script '${err.event}' failed${err.pkgid ? ` for ${err.pkgid}` : ""}`));
|
|
1127
1149
|
if (err.path) {
|
|
@@ -1202,9 +1224,7 @@ const commands = {
|
|
|
1202
1224
|
"new-tag": { args: "<flag boolean>", desc: "Install as new tag even if same version exists" }
|
|
1203
1225
|
},
|
|
1204
1226
|
async exec(cmd) {
|
|
1205
|
-
|
|
1206
|
-
const tag = cmd.getParent()?.opts?.tag;
|
|
1207
|
-
const fynGlobal = new FynGlobal({ globalDir: cmd.opts?.dir, yes: cmd.opts?.yes, tag });
|
|
1227
|
+
const fynGlobal = await makeFynGlobal(cmd, { yes: cmd.opts?.yes });
|
|
1208
1228
|
const packages = cmd.args?.packages || [];
|
|
1209
1229
|
if (packages.length === 0) {
|
|
1210
1230
|
logger.error("No packages specified");
|
|
@@ -1229,11 +1249,9 @@ const commands = {
|
|
|
1229
1249
|
"yes": { alias: "y", desc: "Auto-confirm all prompts" }
|
|
1230
1250
|
},
|
|
1231
1251
|
async exec(cmd) {
|
|
1232
|
-
|
|
1233
|
-
const tag = cmd.getParent()?.opts?.tag;
|
|
1234
|
-
const fynGlobal = new FynGlobal({ globalDir: cmd.opts?.dir, yes: cmd.opts?.yes, tag });
|
|
1252
|
+
const fynGlobal = await makeFynGlobal(cmd, { yes: cmd.opts?.yes });
|
|
1235
1253
|
const packageSpec = cmd.args?.package;
|
|
1236
|
-
if (!packageSpec && !tag) {
|
|
1254
|
+
if (!packageSpec && !fynGlobal.tag) {
|
|
1237
1255
|
logger.error("No package specified");
|
|
1238
1256
|
logger.info("Usage: fyn global remove <name>[@<version>]");
|
|
1239
1257
|
logger.info(" Or: fyn global --tag=<tag> remove");
|
|
@@ -1252,11 +1270,9 @@ const commands = {
|
|
|
1252
1270
|
"dir": { args: "<dir string>", desc: "Directory for global packages (default: ~/.fyn/global)" }
|
|
1253
1271
|
},
|
|
1254
1272
|
async exec(cmd) {
|
|
1255
|
-
|
|
1256
|
-
const tag = cmd.getParent()?.opts?.tag;
|
|
1257
|
-
const fynGlobal = new FynGlobal({ globalDir: cmd.opts?.dir, tag });
|
|
1273
|
+
const fynGlobal = await makeFynGlobal(cmd);
|
|
1258
1274
|
const packageSpec = cmd.args?.package;
|
|
1259
|
-
if (!packageSpec && !tag) {
|
|
1275
|
+
if (!packageSpec && !fynGlobal.tag) {
|
|
1260
1276
|
logger.error("No package specified");
|
|
1261
1277
|
logger.info("Usage: fyn global link <name>@<version>");
|
|
1262
1278
|
logger.info(" Or: fyn global --tag=<tag> link");
|
|
@@ -1276,9 +1292,7 @@ const commands = {
|
|
|
1276
1292
|
"dir": { args: "<dir string>", desc: "Directory for global packages (default: ~/.fyn/global)" }
|
|
1277
1293
|
},
|
|
1278
1294
|
async exec(cmd) {
|
|
1279
|
-
|
|
1280
|
-
const tag = cmd.getParent()?.opts?.tag;
|
|
1281
|
-
const fynGlobal = new FynGlobal({ globalDir: cmd.opts?.dir, tag });
|
|
1295
|
+
const fynGlobal = await makeFynGlobal(cmd);
|
|
1282
1296
|
await fynGlobal.listGlobalPackages(cmd.args?.name);
|
|
1283
1297
|
}
|
|
1284
1298
|
},
|
|
@@ -1289,9 +1303,7 @@ const commands = {
|
|
|
1289
1303
|
"dir": { args: "<dir string>", desc: "Directory for global packages (default: ~/.fyn/global)" }
|
|
1290
1304
|
},
|
|
1291
1305
|
async exec(cmd) {
|
|
1292
|
-
|
|
1293
|
-
const tag = cmd.getParent()?.opts?.tag;
|
|
1294
|
-
const fynGlobal = new FynGlobal({ globalDir: cmd.opts?.dir, tag });
|
|
1306
|
+
const fynGlobal = await makeFynGlobal(cmd);
|
|
1295
1307
|
const packageSpec = cmd.args?.package;
|
|
1296
1308
|
const updated = await fynGlobal.updateGlobalPackage(packageSpec);
|
|
1297
1309
|
if (!updated) {
|
|
@@ -1306,9 +1318,7 @@ const commands = {
|
|
|
1306
1318
|
"dir": { args: "<dir string>", desc: "Directory for global packages (default: ~/.fyn/global)" }
|
|
1307
1319
|
},
|
|
1308
1320
|
async exec(cmd) {
|
|
1309
|
-
|
|
1310
|
-
const tag = cmd.getParent()?.opts?.tag;
|
|
1311
|
-
const fynGlobal = new FynGlobal({ globalDir: cmd.opts?.dir, tag });
|
|
1321
|
+
const fynGlobal = await makeFynGlobal(cmd);
|
|
1312
1322
|
await fynGlobal.useNodeVersion(cmd.args?.version);
|
|
1313
1323
|
}
|
|
1314
1324
|
},
|
|
@@ -1319,8 +1329,7 @@ const commands = {
|
|
|
1319
1329
|
"dir": { args: "<dir string>", desc: "Directory for global packages (default: ~/.fyn/global)" }
|
|
1320
1330
|
},
|
|
1321
1331
|
async exec(cmd) {
|
|
1322
|
-
|
|
1323
|
-
const fynGlobal = new FynGlobal({ globalDir: cmd.opts?.dir });
|
|
1332
|
+
const fynGlobal = await makeFynGlobal(cmd);
|
|
1324
1333
|
const packageName = cmd.args?.package;
|
|
1325
1334
|
const removed = await fynGlobal.cleanupPackage(packageName);
|
|
1326
1335
|
if (removed === 0) {
|
|
@@ -1336,9 +1345,7 @@ const commands = {
|
|
|
1336
1345
|
"dir": { args: "<dir string>", desc: "Directory for global packages (default: ~/.fyn/global)" }
|
|
1337
1346
|
},
|
|
1338
1347
|
async exec(cmd) {
|
|
1339
|
-
|
|
1340
|
-
const tag = cmd.getParent()?.opts?.tag;
|
|
1341
|
-
const fynGlobal = new FynGlobal({ globalDir: cmd.opts?.dir, tag });
|
|
1348
|
+
const fynGlobal = await makeFynGlobal(cmd);
|
|
1342
1349
|
fynGlobal.showPathSetup();
|
|
1343
1350
|
}
|
|
1344
1351
|
}
|
|
@@ -1420,6 +1427,9 @@ module.exports = {
|
|
|
1420
1427
|
run,
|
|
1421
1428
|
fun,
|
|
1422
1429
|
nodeGyp,
|
|
1430
|
+
getRunExitCode,
|
|
1431
|
+
pickEnvOptions,
|
|
1432
|
+
setLockfile,
|
|
1423
1433
|
hardLinkDir
|
|
1424
1434
|
};
|
|
1425
1435
|
|
|
@@ -1686,6 +1696,7 @@ class ShowStat {
|
|
|
1686
1696
|
return this._show(pkgIds);
|
|
1687
1697
|
}).catch((err) => {
|
|
1688
1698
|
logger.error(err);
|
|
1699
|
+
throw err;
|
|
1689
1700
|
}).finally(() => {
|
|
1690
1701
|
logger.removeItem(FETCH_META);
|
|
1691
1702
|
});
|
|
@@ -1977,10 +1988,26 @@ module.exports.__TEST__ = {
|
|
|
1977
1988
|
/***/ "./lib/cacache-util.ts":
|
|
1978
1989
|
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
|
|
1979
1990
|
|
|
1991
|
+
"use strict";
|
|
1992
|
+
|
|
1980
1993
|
const cacache = __webpack_require__("./node_modules/.f/_/cacache/20.0.1/cacache/lib/index.js");
|
|
1981
1994
|
const fs = (__webpack_require__("fs").promises);
|
|
1982
1995
|
const path = __webpack_require__("path");
|
|
1983
1996
|
const crypto = __webpack_require__("crypto");
|
|
1997
|
+
function hashKey(key) {
|
|
1998
|
+
return crypto.createHash("sha256").update(key).digest("hex");
|
|
1999
|
+
}
|
|
2000
|
+
function getBucketPath(cache, key) {
|
|
2001
|
+
const hashed = hashKey(key);
|
|
2002
|
+
const indexV = (__webpack_require__("./node_modules/.f/_/cacache/20.0.1/cacache/package.json")["cache-version"].index);
|
|
2003
|
+
return path.join(
|
|
2004
|
+
cache,
|
|
2005
|
+
`index-v${indexV}`,
|
|
2006
|
+
hashed.slice(0, 2),
|
|
2007
|
+
hashed.slice(2, 4),
|
|
2008
|
+
hashed.slice(4)
|
|
2009
|
+
);
|
|
2010
|
+
}
|
|
1984
2011
|
async function refreshCacheEntry(cache, key) {
|
|
1985
2012
|
const bucket = getBucketPath(cache, key);
|
|
1986
2013
|
const time = /* @__PURE__ */ new Date();
|
|
@@ -2007,20 +2034,6 @@ async function getCacheInfoWithRefreshTime(cache, key) {
|
|
|
2007
2034
|
throw err;
|
|
2008
2035
|
}
|
|
2009
2036
|
}
|
|
2010
|
-
function getBucketPath(cache, key) {
|
|
2011
|
-
const hashed = hashKey(key);
|
|
2012
|
-
const indexV = (__webpack_require__("./node_modules/.f/_/cacache/20.0.1/cacache/package.json")["cache-version"].index);
|
|
2013
|
-
return path.join(
|
|
2014
|
-
cache,
|
|
2015
|
-
`index-v${indexV}`,
|
|
2016
|
-
hashed.slice(0, 2),
|
|
2017
|
-
hashed.slice(2, 4),
|
|
2018
|
-
hashed.slice(4)
|
|
2019
|
-
);
|
|
2020
|
-
}
|
|
2021
|
-
function hashKey(key) {
|
|
2022
|
-
return crypto.createHash("sha256").update(key).digest("hex");
|
|
2023
|
-
}
|
|
2024
2037
|
module.exports = {
|
|
2025
2038
|
refreshCacheEntry,
|
|
2026
2039
|
getCacheInfoWithRefreshTime,
|
|
@@ -2105,9 +2118,12 @@ class DepData {
|
|
|
2105
2118
|
return this.getPkgsData(item.optFailed)[item.name];
|
|
2106
2119
|
}
|
|
2107
2120
|
getPkgById(id) {
|
|
2108
|
-
const
|
|
2109
|
-
const
|
|
2110
|
-
|
|
2121
|
+
const lastAt = id.lastIndexOf("@");
|
|
2122
|
+
const sep = lastAt > 0 ? lastAt : -1;
|
|
2123
|
+
const name = sep > 0 ? id.slice(0, sep) : id;
|
|
2124
|
+
const version = sep > 0 ? id.slice(sep + 1) : void 0;
|
|
2125
|
+
const x = this.getPkgsData()[name];
|
|
2126
|
+
return version ? x[version] : x;
|
|
2111
2127
|
}
|
|
2112
2128
|
eachVersion(cb) {
|
|
2113
2129
|
const pkgs = this.pkgs;
|
|
@@ -2740,6 +2756,7 @@ const unlock = util.promisify(lockfile.unlock);
|
|
|
2740
2756
|
class FynGlobal {
|
|
2741
2757
|
/**
|
|
2742
2758
|
* Create a FynGlobal instance
|
|
2759
|
+
*
|
|
2743
2760
|
* @param {Object} options - Configuration options
|
|
2744
2761
|
* @param {string} [options.globalDir] - Root directory for global packages (default: ~/.fyn/global)
|
|
2745
2762
|
* @param {string} [options.registry] - NPM registry URL (default: https://registry.npmjs.org)
|
|
@@ -2764,21 +2781,24 @@ class FynGlobal {
|
|
|
2764
2781
|
}
|
|
2765
2782
|
/**
|
|
2766
2783
|
* Create a Fyn instance for global package installation
|
|
2784
|
+
*
|
|
2767
2785
|
* @param {string} cwd - Working directory for the install
|
|
2768
2786
|
* @param {boolean} fynlocal - Whether this is a local package
|
|
2769
2787
|
* @returns {Fyn} Configured Fyn instance
|
|
2770
2788
|
*/
|
|
2771
2789
|
_createFyn(cwd, fynlocal) {
|
|
2772
2790
|
process.env.FYN_CENTRAL_DIR = Path.join(this.globalRoot, "_central-storage");
|
|
2791
|
+
const fynOpts = this.options.fynOpts || {};
|
|
2773
2792
|
return new Fyn({
|
|
2774
2793
|
opts: {
|
|
2794
|
+
...fynOpts,
|
|
2775
2795
|
cwd,
|
|
2776
2796
|
targetDir: "node_modules",
|
|
2777
2797
|
centralStore: true,
|
|
2778
2798
|
lockfile: true,
|
|
2779
2799
|
fynlocal,
|
|
2780
2800
|
sourceMaps: false,
|
|
2781
|
-
registry: this.options.registry || "https://registry.npmjs.org",
|
|
2801
|
+
registry: this.options.registry || fynOpts.registry || "https://registry.npmjs.org",
|
|
2782
2802
|
layout: "normal",
|
|
2783
2803
|
flattenTop: true
|
|
2784
2804
|
},
|
|
@@ -2801,6 +2821,7 @@ class FynGlobal {
|
|
|
2801
2821
|
}
|
|
2802
2822
|
/**
|
|
2803
2823
|
* Read the installed.json registry
|
|
2824
|
+
*
|
|
2804
2825
|
* @returns {Object} Registry object with packages info
|
|
2805
2826
|
*/
|
|
2806
2827
|
async readInstalledJson() {
|
|
@@ -2820,6 +2841,7 @@ class FynGlobal {
|
|
|
2820
2841
|
}
|
|
2821
2842
|
/**
|
|
2822
2843
|
* Get all versions of a package from the registry
|
|
2844
|
+
*
|
|
2823
2845
|
* @param {string} packageName
|
|
2824
2846
|
* @returns {Array} Array of version info objects
|
|
2825
2847
|
*/
|
|
@@ -2829,6 +2851,7 @@ class FynGlobal {
|
|
|
2829
2851
|
}
|
|
2830
2852
|
/**
|
|
2831
2853
|
* Get the linked version of a package
|
|
2854
|
+
*
|
|
2832
2855
|
* @param {string} packageName
|
|
2833
2856
|
* @returns {Object|null} Version info or null
|
|
2834
2857
|
*/
|
|
@@ -2838,6 +2861,7 @@ class FynGlobal {
|
|
|
2838
2861
|
}
|
|
2839
2862
|
/**
|
|
2840
2863
|
* Find package info by tag (e.g., g1, g2)
|
|
2864
|
+
*
|
|
2841
2865
|
* @param {string} tag - The tag to find
|
|
2842
2866
|
* @returns {Object|null} Object with packageName and versionInfo, or null if not found
|
|
2843
2867
|
*/
|
|
@@ -2854,6 +2878,7 @@ class FynGlobal {
|
|
|
2854
2878
|
}
|
|
2855
2879
|
/**
|
|
2856
2880
|
* Validate that the tag option points to an existing installation
|
|
2881
|
+
*
|
|
2857
2882
|
* @returns {Object} Object with packageName and versionInfo
|
|
2858
2883
|
* @throws {Error} If tag is set but doesn't exist
|
|
2859
2884
|
*/
|
|
@@ -2884,14 +2909,19 @@ class FynGlobal {
|
|
|
2884
2909
|
}
|
|
2885
2910
|
/**
|
|
2886
2911
|
* Remove a version from the registry
|
|
2912
|
+
*
|
|
2913
|
+
* @param {string} packageName - package name
|
|
2914
|
+
* @param {string} dir - the tag dir (e.g. "g1"); the unique key of an entry.
|
|
2915
|
+
* The same version can exist under multiple tag dirs (--new-tag), so entries
|
|
2916
|
+
* must be identified by dir, not by version string.
|
|
2887
2917
|
*/
|
|
2888
|
-
async removeFromRegistry(packageName,
|
|
2918
|
+
async removeFromRegistry(packageName, dir) {
|
|
2889
2919
|
const registry = await this.readInstalledJson();
|
|
2890
2920
|
if (!registry.packages[packageName]) {
|
|
2891
2921
|
return;
|
|
2892
2922
|
}
|
|
2893
2923
|
const versions = registry.packages[packageName].versions;
|
|
2894
|
-
const idx = versions.findIndex((v) => v.
|
|
2924
|
+
const idx = versions.findIndex((v) => v.dir === dir);
|
|
2895
2925
|
if (idx >= 0) {
|
|
2896
2926
|
versions.splice(idx, 1);
|
|
2897
2927
|
if (versions.length === 0) {
|
|
@@ -3125,6 +3155,7 @@ class FynGlobal {
|
|
|
3125
3155
|
}
|
|
3126
3156
|
/**
|
|
3127
3157
|
* Link bin executables to global bin directory
|
|
3158
|
+
*
|
|
3128
3159
|
* @param {string} gId - Package directory ID (e.g., "g1")
|
|
3129
3160
|
* @param {Object} bins - Map of binName -> binPath
|
|
3130
3161
|
* @param {boolean} force - If true, overwrite existing bins
|
|
@@ -3158,6 +3189,7 @@ class FynGlobal {
|
|
|
3158
3189
|
* - Latest version wins (becomes linked)
|
|
3159
3190
|
* - Prompts if newer version available when installing older
|
|
3160
3191
|
* - Prompts to remove old versions after installing new
|
|
3192
|
+
*
|
|
3161
3193
|
* @param {string} packageSpec - Package spec to install
|
|
3162
3194
|
* @param {Object} [options] - Install options
|
|
3163
3195
|
* @param {boolean} [options.newTag] - Install as new tag even if same version exists
|
|
@@ -3209,7 +3241,7 @@ class FynGlobal {
|
|
|
3209
3241
|
if (!existingExact.linked) {
|
|
3210
3242
|
const linkIt = await this.promptYesNo(`Link this version to make it active?`);
|
|
3211
3243
|
if (linkIt) {
|
|
3212
|
-
await this.linkPackageVersion(packageName
|
|
3244
|
+
await this.linkPackageVersion(`${packageName}@${existingExact.version}`);
|
|
3213
3245
|
}
|
|
3214
3246
|
}
|
|
3215
3247
|
return false;
|
|
@@ -3256,7 +3288,7 @@ class FynGlobal {
|
|
|
3256
3288
|
if (shouldLink) {
|
|
3257
3289
|
for (const existing of existingVersions) {
|
|
3258
3290
|
if (existing.linked) {
|
|
3259
|
-
await this.unlinkBinsForVersion(packageName, existing.
|
|
3291
|
+
await this.unlinkBinsForVersion(packageName, existing.dir);
|
|
3260
3292
|
existing.linked = false;
|
|
3261
3293
|
await this.addToRegistry(packageName, existing);
|
|
3262
3294
|
}
|
|
@@ -3291,7 +3323,7 @@ class FynGlobal {
|
|
|
3291
3323
|
if (removeOld) {
|
|
3292
3324
|
for (const existing of existingVersions) {
|
|
3293
3325
|
if (existing.version !== installedVersion) {
|
|
3294
|
-
await this.removeVersion(packageName, existing.
|
|
3326
|
+
await this.removeVersion(packageName, existing.dir);
|
|
3295
3327
|
logger.info(`Removed ${packageName}@${existing.version}`);
|
|
3296
3328
|
}
|
|
3297
3329
|
}
|
|
@@ -3315,9 +3347,9 @@ class FynGlobal {
|
|
|
3315
3347
|
/**
|
|
3316
3348
|
* Unlink bins for a specific version
|
|
3317
3349
|
*/
|
|
3318
|
-
async unlinkBinsForVersion(packageName,
|
|
3350
|
+
async unlinkBinsForVersion(packageName, dir) {
|
|
3319
3351
|
const versions = await this.getPackageVersions(packageName);
|
|
3320
|
-
const versionInfo = versions.find((v) => v.
|
|
3352
|
+
const versionInfo = versions.find((v) => v.dir === dir);
|
|
3321
3353
|
if (!versionInfo) return;
|
|
3322
3354
|
const binLinker = this._getBinLinker();
|
|
3323
3355
|
const bins = this._getVersionBinTargets(versionInfo);
|
|
@@ -3331,24 +3363,30 @@ class FynGlobal {
|
|
|
3331
3363
|
}
|
|
3332
3364
|
}
|
|
3333
3365
|
/**
|
|
3334
|
-
* Remove a specific
|
|
3366
|
+
* Remove a specific installed entry of a package, identified by its tag dir
|
|
3367
|
+
* (the unique key — the same version may exist under several tag dirs).
|
|
3368
|
+
*
|
|
3369
|
+
* @param {string} packageName - package name
|
|
3370
|
+
* @param {string} dir - the entry's tag dir (e.g. "g1")
|
|
3371
|
+
* @returns {boolean} true if an entry was removed
|
|
3335
3372
|
*/
|
|
3336
|
-
async removeVersion(packageName,
|
|
3373
|
+
async removeVersion(packageName, dir) {
|
|
3337
3374
|
const versions = await this.getPackageVersions(packageName);
|
|
3338
|
-
const versionInfo = versions.find((v) => v.
|
|
3375
|
+
const versionInfo = versions.find((v) => v.dir === dir);
|
|
3339
3376
|
if (!versionInfo) {
|
|
3340
3377
|
return false;
|
|
3341
3378
|
}
|
|
3342
3379
|
if (versionInfo.linked) {
|
|
3343
|
-
await this.unlinkBinsForVersion(packageName,
|
|
3380
|
+
await this.unlinkBinsForVersion(packageName, dir);
|
|
3344
3381
|
}
|
|
3345
3382
|
const pkgDir = Path.join(this.packagesDir, versionInfo.dir);
|
|
3346
3383
|
await Fs.$.rimraf(pkgDir);
|
|
3347
|
-
await this.removeFromRegistry(packageName,
|
|
3384
|
+
await this.removeFromRegistry(packageName, dir);
|
|
3348
3385
|
return true;
|
|
3349
3386
|
}
|
|
3350
3387
|
/**
|
|
3351
3388
|
* Remove globally installed package version(s)
|
|
3389
|
+
*
|
|
3352
3390
|
* @param {string} packageSpec - Package name or name@semver pattern
|
|
3353
3391
|
* - name: remove all versions (warns if multiple, won't remove linked unless only one)
|
|
3354
3392
|
* - name@version: remove exact version
|
|
@@ -3359,11 +3397,12 @@ class FynGlobal {
|
|
|
3359
3397
|
if (this.tag) {
|
|
3360
3398
|
const found = await this.validateTag();
|
|
3361
3399
|
logger.info(`Removing ${found.packageName}@${found.versionInfo.version} (${this.tag})`);
|
|
3362
|
-
await this.removeVersion(found.packageName, found.versionInfo.
|
|
3400
|
+
await this.removeVersion(found.packageName, found.versionInfo.dir);
|
|
3363
3401
|
logger.info(`Removed ${found.packageName}@${found.versionInfo.version}`);
|
|
3364
3402
|
return true;
|
|
3365
3403
|
}
|
|
3366
|
-
let packageName
|
|
3404
|
+
let packageName;
|
|
3405
|
+
let versionSpec;
|
|
3367
3406
|
if (packageSpec.startsWith("@")) {
|
|
3368
3407
|
const lastAt = packageSpec.lastIndexOf("@");
|
|
3369
3408
|
if (lastAt > 0 && lastAt !== packageSpec.indexOf("@")) {
|
|
@@ -3418,13 +3457,14 @@ class FynGlobal {
|
|
|
3418
3457
|
}
|
|
3419
3458
|
}
|
|
3420
3459
|
for (const versionInfo of toRemove) {
|
|
3421
|
-
await this.removeVersion(packageName, versionInfo.
|
|
3460
|
+
await this.removeVersion(packageName, versionInfo.dir);
|
|
3422
3461
|
logger.info(`Removed ${packageName}@${versionInfo.version}`);
|
|
3423
3462
|
}
|
|
3424
3463
|
return true;
|
|
3425
3464
|
}
|
|
3426
3465
|
/**
|
|
3427
3466
|
* List globally installed packages
|
|
3467
|
+
*
|
|
3428
3468
|
* @param {string} [filterName] - Optional package name to filter by
|
|
3429
3469
|
*/
|
|
3430
3470
|
async listGlobalPackages(filterName) {
|
|
@@ -3482,10 +3522,13 @@ ${packageName}:`);
|
|
|
3482
3522
|
}
|
|
3483
3523
|
/**
|
|
3484
3524
|
* Link (activate) a specific version of a package
|
|
3525
|
+
*
|
|
3485
3526
|
* @param {string} packageSpec - Package name@version to link, or ignored if --tag is specified
|
|
3486
3527
|
*/
|
|
3487
3528
|
async linkPackageVersion(packageSpec) {
|
|
3488
|
-
let packageName
|
|
3529
|
+
let packageName;
|
|
3530
|
+
let version;
|
|
3531
|
+
let targetVersion;
|
|
3489
3532
|
if (this.tag) {
|
|
3490
3533
|
const found = await this.validateTag();
|
|
3491
3534
|
packageName = found.packageName;
|
|
@@ -3539,7 +3582,7 @@ Use: fyn global link ${packageName}@<version>`);
|
|
|
3539
3582
|
const versions = await this.getPackageVersions(packageName);
|
|
3540
3583
|
const currentLinked = versions.find((v) => v.linked);
|
|
3541
3584
|
if (currentLinked) {
|
|
3542
|
-
await this.unlinkBinsForVersion(packageName, currentLinked.
|
|
3585
|
+
await this.unlinkBinsForVersion(packageName, currentLinked.dir);
|
|
3543
3586
|
}
|
|
3544
3587
|
const pkgDir = Path.join(this.packagesDir, targetVersion.dir);
|
|
3545
3588
|
const bins = await this.discoverBins(pkgDir, packageName);
|
|
@@ -3553,6 +3596,7 @@ Use: fyn global link ${packageName}@<version>`);
|
|
|
3553
3596
|
}
|
|
3554
3597
|
/**
|
|
3555
3598
|
* Find a package by its local path
|
|
3599
|
+
*
|
|
3556
3600
|
* @param {string} localPath - The local path to search for
|
|
3557
3601
|
* @returns {Object|null} Object with packageName and versions, or null
|
|
3558
3602
|
*/
|
|
@@ -3572,6 +3616,7 @@ Use: fyn global link ${packageName}@<version>`);
|
|
|
3572
3616
|
}
|
|
3573
3617
|
/**
|
|
3574
3618
|
* Update a globally installed package (linked version or specific tag)
|
|
3619
|
+
*
|
|
3575
3620
|
* @param {string} packageSpec - Package name or local path
|
|
3576
3621
|
*/
|
|
3577
3622
|
async updateGlobalPackage(packageSpec) {
|
|
@@ -3697,6 +3742,7 @@ Use: fyn global link ${packageName}@<version>`);
|
|
|
3697
3742
|
}
|
|
3698
3743
|
/**
|
|
3699
3744
|
* Cleanup non-linked versions of a package
|
|
3745
|
+
*
|
|
3700
3746
|
* @param {string} [packageName] - Package name to cleanup, or all packages if not specified
|
|
3701
3747
|
* @returns {number} Number of versions removed
|
|
3702
3748
|
*/
|
|
@@ -3726,7 +3772,7 @@ Use: fyn global link ${packageName}@<version>`);
|
|
|
3726
3772
|
continue;
|
|
3727
3773
|
}
|
|
3728
3774
|
for (const v of nonLinked) {
|
|
3729
|
-
await this.removeVersion(pkgName, v.
|
|
3775
|
+
await this.removeVersion(pkgName, v.dir);
|
|
3730
3776
|
logger.info(`Removed ${pkgName}@${v.version} (${v.dir})`);
|
|
3731
3777
|
totalRemoved++;
|
|
3732
3778
|
}
|
|
@@ -3782,6 +3828,7 @@ const fynTil = __webpack_require__("./lib/util/fyntil.ts");
|
|
|
3782
3828
|
const FynCentral = __webpack_require__("./lib/fyn-central.ts");
|
|
3783
3829
|
const xaa = __webpack_require__("./lib/util/xaa.ts");
|
|
3784
3830
|
const { checkPkgNeedInstall } = __webpack_require__("./lib/util/check-pkg-need-install.ts");
|
|
3831
|
+
const { localExportsNeedInstall } = __webpack_require__("./lib/local-exports.ts");
|
|
3785
3832
|
const lockfile = __webpack_require__("./node_modules/.f/_/lockfile/1.0.4/lockfile/lockfile.js");
|
|
3786
3833
|
const createLock = util.promisify(lockfile.lock);
|
|
3787
3834
|
const unlock = util.promisify(lockfile.unlock);
|
|
@@ -3928,6 +3975,7 @@ class Fyn {
|
|
|
3928
3975
|
}
|
|
3929
3976
|
/**
|
|
3930
3977
|
* Check user production mode option against saved install config in node_modules
|
|
3978
|
+
*
|
|
3931
3979
|
* @remarks - this._installConfig must've been initialized
|
|
3932
3980
|
* @returns nothing
|
|
3933
3981
|
*/
|
|
@@ -3985,13 +4033,13 @@ class Fyn {
|
|
|
3985
4033
|
const fynInstallConfig = JSON.parse(await Fs.readFile(filename));
|
|
3986
4034
|
logger.debug("loaded fynInstallConfig", fynInstallConfig);
|
|
3987
4035
|
const { layout } = fynInstallConfig;
|
|
3988
|
-
if (layout && layout !== this.
|
|
4036
|
+
if (layout && layout !== this._options.layout) {
|
|
3989
4037
|
if (this._cliSource.layout !== "default") {
|
|
3990
4038
|
logger.warn(
|
|
3991
|
-
`Forcing layout to ${layout} from ${this.
|
|
4039
|
+
`Forcing layout to ${layout} from ${this._options.layout} because your existing node_modules uses that. To change it, please remove node_modules first.`
|
|
3992
4040
|
);
|
|
3993
4041
|
}
|
|
3994
|
-
this.
|
|
4042
|
+
this._options.layout = layout;
|
|
3995
4043
|
}
|
|
3996
4044
|
const recordedShort = fynInstallConfig.shortPkgDir === void 0 ? true : fynInstallConfig.shortPkgDir;
|
|
3997
4045
|
if (recordedShort !== this._shortPkgDir) {
|
|
@@ -4112,6 +4160,7 @@ class Fyn {
|
|
|
4112
4160
|
}
|
|
4113
4161
|
/**
|
|
4114
4162
|
* Get the version of a direct dependency from package.json
|
|
4163
|
+
*
|
|
4115
4164
|
* @param {string} pkgName - Package name to look up
|
|
4116
4165
|
* @returns {string|null} The version or null if not found
|
|
4117
4166
|
*/
|
|
@@ -4186,6 +4235,12 @@ class Fyn {
|
|
|
4186
4235
|
return true;
|
|
4187
4236
|
}
|
|
4188
4237
|
}
|
|
4238
|
+
if (await localExportsNeedInstall({
|
|
4239
|
+
cwd: this._cwd,
|
|
4240
|
+
manifest: this._installConfig.localExports
|
|
4241
|
+
})) {
|
|
4242
|
+
return true;
|
|
4243
|
+
}
|
|
4189
4244
|
return false;
|
|
4190
4245
|
}
|
|
4191
4246
|
setLocalDeps(localsByDepth) {
|
|
@@ -4200,6 +4255,9 @@ class Fyn {
|
|
|
4200
4255
|
setLocalPkgLinks(localLinks) {
|
|
4201
4256
|
this._installConfig.localPkgLinks = localLinks;
|
|
4202
4257
|
}
|
|
4258
|
+
setLocalExports(manifest) {
|
|
4259
|
+
this._installConfig.localExports = manifest;
|
|
4260
|
+
}
|
|
4203
4261
|
// save the config to outputDir
|
|
4204
4262
|
async saveInstallConfig() {
|
|
4205
4263
|
const outputDir = this.getOutputDir();
|
|
@@ -4216,7 +4274,7 @@ class Fyn {
|
|
|
4216
4274
|
time: Date.now() + 5,
|
|
4217
4275
|
centralDir,
|
|
4218
4276
|
production: this.production,
|
|
4219
|
-
layout: this.
|
|
4277
|
+
layout: this._options.layout,
|
|
4220
4278
|
shortPkgDir: this._shortPkgDir
|
|
4221
4279
|
// not a good idea to save --run-npm options to install config because
|
|
4222
4280
|
// future fyn install will automatically run them and would be unexpected.
|
|
@@ -4253,7 +4311,7 @@ class Fyn {
|
|
|
4253
4311
|
let pkgFile;
|
|
4254
4312
|
if (options.pkgFile === "package.json") {
|
|
4255
4313
|
let foundDir = null;
|
|
4256
|
-
|
|
4314
|
+
pathUpEach(this._cwd, (path) => {
|
|
4257
4315
|
const testPath = Path.join(path, "package.json");
|
|
4258
4316
|
if (Fs.existsSync(testPath)) {
|
|
4259
4317
|
foundDir = path;
|
|
@@ -4337,6 +4395,46 @@ class Fyn {
|
|
|
4337
4395
|
get showDeprecated() {
|
|
4338
4396
|
return this._options.showDeprecated && "show-deprecated";
|
|
4339
4397
|
}
|
|
4398
|
+
// package.json `fyn.allowScripts` whitelist - maps `name@spec` or
|
|
4399
|
+
// `name@version` to the lifecycle scripts allowed for packages that did not
|
|
4400
|
+
// come from a configured registry (github/git/url tarball deps).
|
|
4401
|
+
get allowScripts() {
|
|
4402
|
+
if (this._allowScripts === void 0 && this._pkg) {
|
|
4403
|
+
this._allowScripts = _.get(this._pkg, ["fyn", "allowScripts"]) || {};
|
|
4404
|
+
}
|
|
4405
|
+
return this._allowScripts || {};
|
|
4406
|
+
}
|
|
4407
|
+
// package.json `fyn.allowTopLevelScripts` - opt-in (default off) to trust the
|
|
4408
|
+
// lifecycle scripts of non-registry packages (github/git/url tarball) that are
|
|
4409
|
+
// declared directly in the top-level package.json, without per-package
|
|
4410
|
+
// `fyn.allowScripts` entries. `true`/`"*"` allows all lifecycle scripts; an
|
|
4411
|
+
// array allows only those script names. Transitive deps stay blocked.
|
|
4412
|
+
get allowTopLevelScripts() {
|
|
4413
|
+
if (this._allowTopLevelScripts === void 0 && this._pkg) {
|
|
4414
|
+
this._allowTopLevelScripts = _.get(this._pkg, ["fyn", "allowTopLevelScripts"]) || false;
|
|
4415
|
+
}
|
|
4416
|
+
return this._allowTopLevelScripts || false;
|
|
4417
|
+
}
|
|
4418
|
+
// Security policy: transitive (non-top-level) dependencies must resolve from
|
|
4419
|
+
// a published registry. git/github/url-tarball sources and unparseable semver
|
|
4420
|
+
// are rejected (hard error). Local (file:/link:/symlink, incl. fynpo
|
|
4421
|
+
// siblings) and `npm:` aliases are accepted. Only the top-level package.json
|
|
4422
|
+
// may declare non-registry deps.
|
|
4423
|
+
//
|
|
4424
|
+
// Default ON. Disable explicitly with the CLI flag
|
|
4425
|
+
// `--no-enforce-registry-deps` or package.json `fyn.enforceRegistryDeps:false`.
|
|
4426
|
+
// Precedence: CLI option (when given) > package.json fyn flag > default (on).
|
|
4427
|
+
get enforceRegistryDeps() {
|
|
4428
|
+
const cliOpt = this._options.enforceRegistryDeps;
|
|
4429
|
+
if (cliOpt !== void 0) {
|
|
4430
|
+
return Boolean(cliOpt);
|
|
4431
|
+
}
|
|
4432
|
+
if (this._enforceRegistryDeps === void 0 && this._pkg) {
|
|
4433
|
+
const pkgOpt = _.get(this._pkg, ["fyn", "enforceRegistryDeps"]);
|
|
4434
|
+
this._enforceRegistryDeps = pkgOpt === void 0 ? true : Boolean(pkgOpt);
|
|
4435
|
+
}
|
|
4436
|
+
return this._enforceRegistryDeps === void 0 ? true : this._enforceRegistryDeps;
|
|
4437
|
+
}
|
|
4340
4438
|
get refreshOptionals() {
|
|
4341
4439
|
return this._options.refreshOptionals;
|
|
4342
4440
|
}
|
|
@@ -4528,6 +4626,7 @@ class Fyn {
|
|
|
4528
4626
|
}
|
|
4529
4627
|
/**
|
|
4530
4628
|
* Scan FV_DIR for modules saved in the ${name}/${version} format
|
|
4629
|
+
*
|
|
4531
4630
|
* @returns {*} pkgs under fv dir with their versions
|
|
4532
4631
|
*/
|
|
4533
4632
|
async loadFvVersions() {
|
|
@@ -4565,7 +4664,7 @@ class Fyn {
|
|
|
4565
4664
|
async createPkgOutDir(dir, keep) {
|
|
4566
4665
|
try {
|
|
4567
4666
|
const r = await Fs.$.mkdirp(dir);
|
|
4568
|
-
if (r ===
|
|
4667
|
+
if (r === void 0 && !keep && dir !== this.getOutputDir()) {
|
|
4569
4668
|
await this.clearPkgOutDir(dir);
|
|
4570
4669
|
}
|
|
4571
4670
|
} catch (err) {
|
|
@@ -4829,6 +4928,373 @@ class LifecycleScripts {
|
|
|
4829
4928
|
module.exports = LifecycleScripts;
|
|
4830
4929
|
|
|
4831
4930
|
|
|
4931
|
+
/***/ }),
|
|
4932
|
+
|
|
4933
|
+
/***/ "./lib/local-exports.ts":
|
|
4934
|
+
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
|
|
4935
|
+
|
|
4936
|
+
"use strict";
|
|
4937
|
+
|
|
4938
|
+
const Path = __webpack_require__("path");
|
|
4939
|
+
const Fs = __webpack_require__("./lib/util/file-ops.ts");
|
|
4940
|
+
const fynTil = __webpack_require__("./lib/util/fyntil.ts");
|
|
4941
|
+
const { getUrlType } = __webpack_require__("./lib/util/lifecycle-script-policy.ts");
|
|
4942
|
+
const DEFAULT_ROOT_DIR = "_fyn";
|
|
4943
|
+
const MANIFEST_FILE = ".fyn-local-exports.json";
|
|
4944
|
+
const MANIFEST_VERSION = 1;
|
|
4945
|
+
const SAFE_NAME = /^[A-Za-z0-9_][A-Za-z0-9._-]*$/;
|
|
4946
|
+
const posixify = (value) => value.split(Path.sep).join("/");
|
|
4947
|
+
const rootOfEntry = (entry) => entry.root || DEFAULT_ROOT_DIR;
|
|
4948
|
+
const emptyManifest = () => ({ version: MANIFEST_VERSION, exports: {} });
|
|
4949
|
+
const packagePathParts = (name) => {
|
|
4950
|
+
const parts = typeof name === "string" ? name.split("/") : [];
|
|
4951
|
+
const scoped = parts.length === 2 && parts[0][0] === "@";
|
|
4952
|
+
const safe = scoped ? SAFE_NAME.test(parts[0].slice(1)) && SAFE_NAME.test(parts[1]) : parts.length === 1 && SAFE_NAME.test(parts[0]);
|
|
4953
|
+
if (!safe) {
|
|
4954
|
+
throw new Error(`Invalid package name for fyn.localExports: ${name}`);
|
|
4955
|
+
}
|
|
4956
|
+
return parts;
|
|
4957
|
+
};
|
|
4958
|
+
const checkExportName = (packageName, exportName) => {
|
|
4959
|
+
if (!SAFE_NAME.test(exportName) || exportName === "." || exportName === "..") {
|
|
4960
|
+
throw new Error(
|
|
4961
|
+
`Invalid fyn.localExports export name ${JSON.stringify(exportName)} in ${packageName}`
|
|
4962
|
+
);
|
|
4963
|
+
}
|
|
4964
|
+
};
|
|
4965
|
+
const normalizeRootDir = (value, ctx) => {
|
|
4966
|
+
if (typeof value !== "string" || !value.trim()) {
|
|
4967
|
+
throw new Error(`${ctx} must be a non-empty relative directory`);
|
|
4968
|
+
}
|
|
4969
|
+
if (Path.isAbsolute(value) || Path.posix.isAbsolute(value) || Path.win32.isAbsolute(value)) {
|
|
4970
|
+
throw new Error(`${ctx} must not be absolute: ${value}`);
|
|
4971
|
+
}
|
|
4972
|
+
const parts = value.split(/[\\/]+/).filter((part) => part && part !== ".");
|
|
4973
|
+
if (parts.length === 0 || parts.includes("..") || parts.includes("node_modules") || parts.includes(".git")) {
|
|
4974
|
+
throw new Error(`Unsafe ${ctx}: ${value}`);
|
|
4975
|
+
}
|
|
4976
|
+
return parts.join("/");
|
|
4977
|
+
};
|
|
4978
|
+
const nestsWithin = (parent, child) => {
|
|
4979
|
+
const relative = Path.posix.relative(parent, child);
|
|
4980
|
+
return relative !== "" && !relative.startsWith("..");
|
|
4981
|
+
};
|
|
4982
|
+
const assertNoNestedRoots = (roots) => {
|
|
4983
|
+
const uniq = [...new Set(roots)];
|
|
4984
|
+
for (const a of uniq) {
|
|
4985
|
+
for (const b of uniq) {
|
|
4986
|
+
if (a !== b && nestsWithin(a, b)) {
|
|
4987
|
+
throw new Error(`fyn local export directories must not nest: ${a} contains ${b}`);
|
|
4988
|
+
}
|
|
4989
|
+
}
|
|
4990
|
+
}
|
|
4991
|
+
};
|
|
4992
|
+
const resolveLocalExportsConfig = (pkg) => {
|
|
4993
|
+
const fyn = pkg && pkg.fyn || {};
|
|
4994
|
+
const defaultDir = fyn.localExportsDir === void 0 ? DEFAULT_ROOT_DIR : normalizeRootDir(fyn.localExportsDir, "fyn.localExportsDir");
|
|
4995
|
+
const byPackage = {};
|
|
4996
|
+
const dirs = fyn.localExportsDirs;
|
|
4997
|
+
if (dirs !== void 0 && dirs !== null) {
|
|
4998
|
+
if (typeof dirs !== "object" || Array.isArray(dirs)) {
|
|
4999
|
+
throw new Error("fyn.localExportsDirs must be an object of package name to directory");
|
|
5000
|
+
}
|
|
5001
|
+
for (const name of Object.keys(dirs)) {
|
|
5002
|
+
packagePathParts(name);
|
|
5003
|
+
byPackage[name] = normalizeRootDir(dirs[name], `fyn.localExportsDirs[${JSON.stringify(name)}]`);
|
|
5004
|
+
}
|
|
5005
|
+
}
|
|
5006
|
+
assertNoNestedRoots([defaultDir, ...Object.values(byPackage)]);
|
|
5007
|
+
return { defaultDir, byPackage };
|
|
5008
|
+
};
|
|
5009
|
+
const rootDirForPackage = (config, name) => config.byPackage && config.byPackage[name] || config.defaultDir;
|
|
5010
|
+
const localExportsScanIgnores = (pkg) => {
|
|
5011
|
+
let config;
|
|
5012
|
+
try {
|
|
5013
|
+
config = resolveLocalExportsConfig(pkg);
|
|
5014
|
+
} catch (err) {
|
|
5015
|
+
return [];
|
|
5016
|
+
}
|
|
5017
|
+
const roots = [config.defaultDir, ...Object.values(config.byPackage)];
|
|
5018
|
+
return [...new Set(roots)].map((root) => `**/${root}`);
|
|
5019
|
+
};
|
|
5020
|
+
const groupByRoot = (exportsMap) => {
|
|
5021
|
+
const byRoot = /* @__PURE__ */ new Map();
|
|
5022
|
+
for (const target of Object.keys(exportsMap)) {
|
|
5023
|
+
const root = rootOfEntry(exportsMap[target]);
|
|
5024
|
+
if (!byRoot.has(root)) {
|
|
5025
|
+
byRoot.set(root, {});
|
|
5026
|
+
}
|
|
5027
|
+
byRoot.get(root)[target] = exportsMap[target];
|
|
5028
|
+
}
|
|
5029
|
+
return byRoot;
|
|
5030
|
+
};
|
|
5031
|
+
const normalizeManifest = (manifest) => {
|
|
5032
|
+
if (!manifest) {
|
|
5033
|
+
return emptyManifest();
|
|
5034
|
+
}
|
|
5035
|
+
if (manifest.version !== MANIFEST_VERSION || !manifest.exports || Array.isArray(manifest.exports) || typeof manifest.exports !== "object") {
|
|
5036
|
+
throw new Error("Invalid fyn local exports manifest");
|
|
5037
|
+
}
|
|
5038
|
+
for (const target of Object.keys(manifest.exports)) {
|
|
5039
|
+
const entry = manifest.exports[target];
|
|
5040
|
+
if (!entry || typeof entry !== "object" || typeof entry.source !== "string" || !entry.source) {
|
|
5041
|
+
throw new Error("Invalid fyn local exports manifest entry");
|
|
5042
|
+
}
|
|
5043
|
+
const root = normalizeRootDir(rootOfEntry(entry), "fyn local exports manifest root");
|
|
5044
|
+
const expectedTarget = posixify(
|
|
5045
|
+
Path.join(root, ...packagePathParts(entry.package), entry.export)
|
|
5046
|
+
);
|
|
5047
|
+
checkExportName(entry.package, entry.export);
|
|
5048
|
+
if (target !== expectedTarget || entry.target !== expectedTarget) {
|
|
5049
|
+
throw new Error(`Invalid fyn local exports manifest target: ${target}`);
|
|
5050
|
+
}
|
|
5051
|
+
}
|
|
5052
|
+
return manifest;
|
|
5053
|
+
};
|
|
5054
|
+
const checkSourcePath = (packageName, sourcePath) => {
|
|
5055
|
+
if (typeof sourcePath !== "string" || !sourcePath.trim()) {
|
|
5056
|
+
throw new Error(`fyn.localExports source for ${packageName} must be a relative directory`);
|
|
5057
|
+
}
|
|
5058
|
+
if (Path.isAbsolute(sourcePath) || Path.posix.isAbsolute(sourcePath) || Path.win32.isAbsolute(sourcePath)) {
|
|
5059
|
+
throw new Error(`fyn.localExports source for ${packageName} must not be absolute`);
|
|
5060
|
+
}
|
|
5061
|
+
const parts = sourcePath.split(/[\\/]+/);
|
|
5062
|
+
if (parts.includes("..") || parts.includes("node_modules") || parts.includes(".git")) {
|
|
5063
|
+
throw new Error(`Unsafe fyn.localExports source ${sourcePath} in ${packageName}`);
|
|
5064
|
+
}
|
|
5065
|
+
};
|
|
5066
|
+
const isInside = (root, child) => {
|
|
5067
|
+
const relative = Path.relative(root, child);
|
|
5068
|
+
return relative !== "" && relative !== ".." && !relative.startsWith(`..${Path.sep}`);
|
|
5069
|
+
};
|
|
5070
|
+
const readOwnedManifest = async (cwd, root) => {
|
|
5071
|
+
const marker = Path.join(cwd, root, MANIFEST_FILE);
|
|
5072
|
+
try {
|
|
5073
|
+
const value = JSON.parse(await Fs.readFile(marker, "utf8"));
|
|
5074
|
+
return normalizeManifest(value);
|
|
5075
|
+
} catch (err) {
|
|
5076
|
+
if (err.code === "ENOENT" || err.code === "ENOTDIR") {
|
|
5077
|
+
return null;
|
|
5078
|
+
}
|
|
5079
|
+
throw new Error(`Invalid ${root} ownership manifest: ${err.message}`);
|
|
5080
|
+
}
|
|
5081
|
+
};
|
|
5082
|
+
const sourcePathFor = (cwd, entry) => Path.resolve(cwd, entry.source);
|
|
5083
|
+
const linkMatches = async (cwd, entry) => {
|
|
5084
|
+
try {
|
|
5085
|
+
const target = await Fs.realpath(Path.resolve(cwd, entry.target));
|
|
5086
|
+
const source = await Fs.realpath(sourcePathFor(cwd, entry));
|
|
5087
|
+
return target === source;
|
|
5088
|
+
} catch (err) {
|
|
5089
|
+
return false;
|
|
5090
|
+
}
|
|
5091
|
+
};
|
|
5092
|
+
async function makeLocalExportsManifest({ cwd, depInfos, config: exportsConfig }) {
|
|
5093
|
+
const resolved = exportsConfig || { defaultDir: DEFAULT_ROOT_DIR, byPackage: {} };
|
|
5094
|
+
const entries = {};
|
|
5095
|
+
const consumerRoot = await Fs.realpath(cwd);
|
|
5096
|
+
for (const depInfo of depInfos) {
|
|
5097
|
+
if (depInfo.local !== "hard" || getUrlType(depInfo) || depInfo.optFailed || depInfo._removed) {
|
|
5098
|
+
continue;
|
|
5099
|
+
}
|
|
5100
|
+
const config = depInfo.json && depInfo.json.fyn && depInfo.json.fyn.localExports;
|
|
5101
|
+
if (config === void 0 || config === false) {
|
|
5102
|
+
continue;
|
|
5103
|
+
}
|
|
5104
|
+
if (!config || Array.isArray(config) || typeof config !== "object") {
|
|
5105
|
+
throw new Error(`fyn.localExports for ${depInfo.name} must be an object or false`);
|
|
5106
|
+
}
|
|
5107
|
+
const packageParts = packagePathParts(depInfo.name);
|
|
5108
|
+
const packageRoot = await Fs.realpath(depInfo.dir);
|
|
5109
|
+
for (const exportName of Object.keys(config).sort()) {
|
|
5110
|
+
const configuredSource = config[exportName];
|
|
5111
|
+
if (configuredSource === false) {
|
|
5112
|
+
continue;
|
|
5113
|
+
}
|
|
5114
|
+
checkExportName(depInfo.name, exportName);
|
|
5115
|
+
checkSourcePath(depInfo.name, configuredSource);
|
|
5116
|
+
const unresolvedSource = Path.resolve(packageRoot, configuredSource);
|
|
5117
|
+
let source;
|
|
5118
|
+
let sourceStat;
|
|
5119
|
+
try {
|
|
5120
|
+
source = await Fs.realpath(unresolvedSource);
|
|
5121
|
+
sourceStat = await Fs.stat(source);
|
|
5122
|
+
} catch (err) {
|
|
5123
|
+
throw new Error(
|
|
5124
|
+
`fyn.localExports source ${configuredSource} in ${depInfo.name} does not exist`
|
|
5125
|
+
);
|
|
5126
|
+
}
|
|
5127
|
+
if (!isInside(packageRoot, source)) {
|
|
5128
|
+
throw new Error(
|
|
5129
|
+
`fyn.localExports source ${configuredSource} in ${depInfo.name} escapes the package`
|
|
5130
|
+
);
|
|
5131
|
+
}
|
|
5132
|
+
if (!sourceStat.isDirectory()) {
|
|
5133
|
+
throw new Error(
|
|
5134
|
+
`fyn.localExports source ${configuredSource} in ${depInfo.name} is not a directory`
|
|
5135
|
+
);
|
|
5136
|
+
}
|
|
5137
|
+
const root = rootDirForPackage(resolved, depInfo.name);
|
|
5138
|
+
const target = posixify(Path.join(root, ...packageParts, exportName));
|
|
5139
|
+
const relativeSource = posixify(Path.relative(consumerRoot, source));
|
|
5140
|
+
const prior = entries[target];
|
|
5141
|
+
if (prior && (prior.source !== relativeSource || prior.version !== depInfo.version)) {
|
|
5142
|
+
throw new Error(
|
|
5143
|
+
`Local export destination collision for ${depInfo.name}@${depInfo.version}: ${target}`
|
|
5144
|
+
);
|
|
5145
|
+
}
|
|
5146
|
+
const targetPath = Path.resolve(consumerRoot, target);
|
|
5147
|
+
entries[target] = {
|
|
5148
|
+
package: depInfo.name,
|
|
5149
|
+
version: depInfo.version,
|
|
5150
|
+
export: exportName,
|
|
5151
|
+
source: relativeSource,
|
|
5152
|
+
target,
|
|
5153
|
+
root,
|
|
5154
|
+
linkTarget: fynTil.isWin32 ? source : posixify(Path.relative(Path.dirname(targetPath), source))
|
|
5155
|
+
};
|
|
5156
|
+
}
|
|
5157
|
+
}
|
|
5158
|
+
const sortedEntries = {};
|
|
5159
|
+
for (const target of Object.keys(entries).sort()) {
|
|
5160
|
+
sortedEntries[target] = entries[target];
|
|
5161
|
+
}
|
|
5162
|
+
return { version: MANIFEST_VERSION, exports: sortedEntries };
|
|
5163
|
+
}
|
|
5164
|
+
async function rootNeedsInstall(cwd, root, exportsForRoot) {
|
|
5165
|
+
const rootManifest = { version: MANIFEST_VERSION, exports: exportsForRoot };
|
|
5166
|
+
let realized;
|
|
5167
|
+
try {
|
|
5168
|
+
realized = await readOwnedManifest(cwd, root);
|
|
5169
|
+
} catch (err) {
|
|
5170
|
+
return true;
|
|
5171
|
+
}
|
|
5172
|
+
if (!realized || JSON.stringify(realized) !== JSON.stringify(rootManifest)) {
|
|
5173
|
+
return true;
|
|
5174
|
+
}
|
|
5175
|
+
for (const target of Object.keys(exportsForRoot)) {
|
|
5176
|
+
if (!await linkMatches(cwd, exportsForRoot[target])) {
|
|
5177
|
+
return true;
|
|
5178
|
+
}
|
|
5179
|
+
}
|
|
5180
|
+
return false;
|
|
5181
|
+
}
|
|
5182
|
+
async function localExportsNeedInstall({ cwd, manifest }) {
|
|
5183
|
+
const desired = normalizeManifest(manifest);
|
|
5184
|
+
const byRoot = groupByRoot(desired.exports);
|
|
5185
|
+
if (byRoot.size === 0) {
|
|
5186
|
+
try {
|
|
5187
|
+
return Boolean(await readOwnedManifest(cwd, DEFAULT_ROOT_DIR));
|
|
5188
|
+
} catch (err) {
|
|
5189
|
+
return false;
|
|
5190
|
+
}
|
|
5191
|
+
}
|
|
5192
|
+
for (const [root, exportsForRoot] of byRoot) {
|
|
5193
|
+
if (await rootNeedsInstall(cwd, root, exportsForRoot)) {
|
|
5194
|
+
return true;
|
|
5195
|
+
}
|
|
5196
|
+
}
|
|
5197
|
+
return false;
|
|
5198
|
+
}
|
|
5199
|
+
async function reconcileOneRoot(cwd, root, exportsForRoot) {
|
|
5200
|
+
const targets = Object.keys(exportsForRoot);
|
|
5201
|
+
const rootPath = Path.join(cwd, root);
|
|
5202
|
+
let owned;
|
|
5203
|
+
try {
|
|
5204
|
+
owned = await readOwnedManifest(cwd, root);
|
|
5205
|
+
} catch (err) {
|
|
5206
|
+
if (targets.length === 0) {
|
|
5207
|
+
return;
|
|
5208
|
+
}
|
|
5209
|
+
throw err;
|
|
5210
|
+
}
|
|
5211
|
+
if (targets.length === 0) {
|
|
5212
|
+
if (owned) {
|
|
5213
|
+
await Fs.$.rimraf(rootPath);
|
|
5214
|
+
}
|
|
5215
|
+
return;
|
|
5216
|
+
}
|
|
5217
|
+
if (await Fs.exists(rootPath) && !owned) {
|
|
5218
|
+
throw new Error(`Refusing to modify ${rootPath} without a fyn ownership manifest`);
|
|
5219
|
+
}
|
|
5220
|
+
if (owned && !await rootNeedsInstall(cwd, root, exportsForRoot)) {
|
|
5221
|
+
return;
|
|
5222
|
+
}
|
|
5223
|
+
const desiredRootManifest = { version: MANIFEST_VERSION, exports: exportsForRoot };
|
|
5224
|
+
const suffix = `${process.pid}-${Date.now()}`;
|
|
5225
|
+
const staging = `${rootPath}.fyn-tmp-${suffix}`;
|
|
5226
|
+
const backup = `${rootPath}.fyn-old-${suffix}`;
|
|
5227
|
+
let movedExisting = false;
|
|
5228
|
+
try {
|
|
5229
|
+
await Fs.$.rimraf(staging);
|
|
5230
|
+
await Fs.$.mkdirp(staging);
|
|
5231
|
+
for (const target of targets) {
|
|
5232
|
+
const entry = exportsForRoot[target];
|
|
5233
|
+
const stagedTarget = Path.join(staging, Path.relative(root, target));
|
|
5234
|
+
const source = sourcePathFor(cwd, entry);
|
|
5235
|
+
const stat = await Fs.stat(source);
|
|
5236
|
+
if (!stat.isDirectory()) {
|
|
5237
|
+
throw new Error(`Local export source is not a directory: ${source}`);
|
|
5238
|
+
}
|
|
5239
|
+
await Fs.$.mkdirp(Path.dirname(stagedTarget));
|
|
5240
|
+
await fynTil.symlinkDir(stagedTarget, source, !fynTil.isWin32);
|
|
5241
|
+
}
|
|
5242
|
+
await Fs.writeFile(
|
|
5243
|
+
Path.join(staging, MANIFEST_FILE),
|
|
5244
|
+
`${JSON.stringify(desiredRootManifest, null, 2)}
|
|
5245
|
+
`
|
|
5246
|
+
);
|
|
5247
|
+
if (owned) {
|
|
5248
|
+
await Fs.$.rimraf(backup);
|
|
5249
|
+
await Fs.rename(rootPath, backup);
|
|
5250
|
+
movedExisting = true;
|
|
5251
|
+
}
|
|
5252
|
+
await Fs.$.mkdirp(Path.dirname(rootPath));
|
|
5253
|
+
await Fs.rename(staging, rootPath);
|
|
5254
|
+
if (movedExisting) {
|
|
5255
|
+
movedExisting = false;
|
|
5256
|
+
await Fs.$.rimraf(backup);
|
|
5257
|
+
}
|
|
5258
|
+
} catch (err) {
|
|
5259
|
+
await Fs.$.rimraf(staging);
|
|
5260
|
+
if (movedExisting) {
|
|
5261
|
+
await Fs.$.rimraf(rootPath);
|
|
5262
|
+
await Fs.rename(backup, rootPath);
|
|
5263
|
+
}
|
|
5264
|
+
throw err;
|
|
5265
|
+
}
|
|
5266
|
+
}
|
|
5267
|
+
async function reconcileLocalExports({ cwd, manifest, previous }) {
|
|
5268
|
+
const desired = normalizeManifest(manifest);
|
|
5269
|
+
const byRoot = groupByRoot(desired.exports);
|
|
5270
|
+
const allRoots = /* @__PURE__ */ new Set([DEFAULT_ROOT_DIR, ...byRoot.keys()]);
|
|
5271
|
+
if (previous) {
|
|
5272
|
+
for (const root of groupByRoot(normalizeManifest(previous).exports).keys()) {
|
|
5273
|
+
allRoots.add(root);
|
|
5274
|
+
}
|
|
5275
|
+
}
|
|
5276
|
+
for (const root of [...allRoots].sort()) {
|
|
5277
|
+
if (!byRoot.has(root)) {
|
|
5278
|
+
await reconcileOneRoot(cwd, root, {});
|
|
5279
|
+
}
|
|
5280
|
+
}
|
|
5281
|
+
for (const root of [...byRoot.keys()].sort()) {
|
|
5282
|
+
await reconcileOneRoot(cwd, root, byRoot.get(root));
|
|
5283
|
+
}
|
|
5284
|
+
}
|
|
5285
|
+
async function syncLocalExports(options) {
|
|
5286
|
+
return reconcileLocalExports(options);
|
|
5287
|
+
}
|
|
5288
|
+
module.exports = {
|
|
5289
|
+
makeLocalExportsManifest,
|
|
5290
|
+
reconcileLocalExports,
|
|
5291
|
+
syncLocalExports,
|
|
5292
|
+
localExportsNeedInstall,
|
|
5293
|
+
resolveLocalExportsConfig,
|
|
5294
|
+
localExportsScanIgnores
|
|
5295
|
+
};
|
|
5296
|
+
|
|
5297
|
+
|
|
4832
5298
|
/***/ }),
|
|
4833
5299
|
|
|
4834
5300
|
/***/ "./lib/local-pkg-builder.ts":
|
|
@@ -4897,7 +5363,12 @@ class LocalPkgBuilder {
|
|
|
4897
5363
|
}, {});
|
|
4898
5364
|
logger.debug("local pkgs for build all paths", allPaths, "uniq paths", uniqPaths);
|
|
4899
5365
|
for (const path of uniqPaths) {
|
|
4900
|
-
|
|
5366
|
+
try {
|
|
5367
|
+
await this.addItem(byPathLookup[path]);
|
|
5368
|
+
} catch (error) {
|
|
5369
|
+
this._startError = error;
|
|
5370
|
+
break;
|
|
5371
|
+
}
|
|
4901
5372
|
}
|
|
4902
5373
|
logger.debug("resolving build local _started promise");
|
|
4903
5374
|
this._started.resolve();
|
|
@@ -4936,6 +5407,9 @@ class LocalPkgBuilder {
|
|
|
4936
5407
|
logger.debug("waiting for local build item start, fullPath:", fullPath);
|
|
4937
5408
|
await this._started.promise;
|
|
4938
5409
|
}
|
|
5410
|
+
if (this._startError) {
|
|
5411
|
+
return { error: this._startError };
|
|
5412
|
+
}
|
|
4939
5413
|
const x = this._waitItems[fullPath];
|
|
4940
5414
|
if (x && x.promise) {
|
|
4941
5415
|
logger.debug("waiting for build local item", fullPath, x);
|
|
@@ -5392,6 +5866,7 @@ module.exports = PkgBinLinker;
|
|
|
5392
5866
|
"use strict";
|
|
5393
5867
|
|
|
5394
5868
|
const Fs = __webpack_require__("./lib/util/file-ops.ts");
|
|
5869
|
+
const Path = __webpack_require__("path");
|
|
5395
5870
|
const PkgBinLinkerBase = __webpack_require__("./lib/pkg-bin-linker-base.ts");
|
|
5396
5871
|
const CYGWIN_LINK = `#!/bin/sh
|
|
5397
5872
|
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
|
@@ -5447,6 +5922,31 @@ class PkgBinLinkerWin32 extends PkgBinLinkerBase {
|
|
|
5447
5922
|
await this._unlinkFile(symlink);
|
|
5448
5923
|
await this._unlinkFile(symlink + ".cmd");
|
|
5449
5924
|
}
|
|
5925
|
+
// Extract the {{TARGET}} path baked into a generated .cmd wrapper (the path
|
|
5926
|
+
// after `%~dp0\`, ignoring the node.exe reference).
|
|
5927
|
+
async _readBinLinkTarget(symlink) {
|
|
5928
|
+
const content = (await Fs.readFile(symlink + ".cmd")).toString();
|
|
5929
|
+
const matches = [...content.matchAll(/%~dp0[\\/]+([^"\r\n]+)/g)].map((m) => m[1]);
|
|
5930
|
+
return matches.find((m) => m !== "node.exe");
|
|
5931
|
+
}
|
|
5932
|
+
//
|
|
5933
|
+
// Platform specific: the "bin" is a pair of regular script files (cygwin +
|
|
5934
|
+
// .cmd), not a symlink, so the base _cleanLink's Fs.access on the wrapper
|
|
5935
|
+
// always succeeds and never cleans a stale bin. Instead, read the wrapper and
|
|
5936
|
+
// remove it only if the target it points to no longer exists.
|
|
5937
|
+
//
|
|
5938
|
+
async _cleanLink(sym) {
|
|
5939
|
+
const symlink = Path.join(this._binDir, sym);
|
|
5940
|
+
try {
|
|
5941
|
+
const target = await this._readBinLinkTarget(symlink);
|
|
5942
|
+
if (target && await Fs.exists(Path.join(this._binDir, target))) {
|
|
5943
|
+
return false;
|
|
5944
|
+
}
|
|
5945
|
+
} catch (e) {
|
|
5946
|
+
}
|
|
5947
|
+
await this._rmBinLink(symlink);
|
|
5948
|
+
return true;
|
|
5949
|
+
}
|
|
5450
5950
|
async _readBinLinks() {
|
|
5451
5951
|
return (await Fs.readdir(this._binDir)).filter((x) => !x.endsWith(".cmd"));
|
|
5452
5952
|
}
|
|
@@ -5931,6 +6431,7 @@ class PkgDepLocker {
|
|
|
5931
6431
|
* - dependencies
|
|
5932
6432
|
* - optionalDependencies
|
|
5933
6433
|
* - devDependencies
|
|
6434
|
+
*
|
|
5934
6435
|
* @param {*} pkgDepItems - dep items generated by makePkgDepItems in pkg-dep-resolver.js
|
|
5935
6436
|
*
|
|
5936
6437
|
* @returns {*} none
|
|
@@ -6160,6 +6661,7 @@ const logFormat = __webpack_require__("./lib/util/log-format.ts");
|
|
|
6160
6661
|
const { LONG_WAIT_META } = __webpack_require__("./lib/log-items.ts");
|
|
6161
6662
|
const { checkPkgOsCpu, relativePath, unSlashNpmScope } = __webpack_require__("./lib/util/fyntil.ts");
|
|
6162
6663
|
const { getDepSection, makeDepStep } = __webpack_require__("./node_modules/.f/_/@fynpo/base/1.1.22-fynlocal_h/@fynpo/base/dist/index.js");
|
|
6664
|
+
const { violatesRegistryPolicy } = __webpack_require__("./lib/util/registry-dep-policy.ts");
|
|
6163
6665
|
const xaa = __webpack_require__("./lib/util/xaa.ts");
|
|
6164
6666
|
const { AggregateError } = __webpack_require__("./node_modules/.f/_/@jchip/error/1.0.3/@jchip/error/dist/index.js");
|
|
6165
6667
|
const Promise = __webpack_require__("./node_modules/.f/_/aveazul/1.1.0/aveazul/cjs-entry.cjs");
|
|
@@ -6426,6 +6928,31 @@ class PkgDepResolver {
|
|
|
6426
6928
|
}
|
|
6427
6929
|
return semver;
|
|
6428
6930
|
}
|
|
6931
|
+
/**
|
|
6932
|
+
* Enforce the `fyn.enforceRegistryDeps` policy on a transitive dep item.
|
|
6933
|
+
* Throws (aborting the install) when the item is a non-registry source or has
|
|
6934
|
+
* an unparseable semver.
|
|
6935
|
+
*
|
|
6936
|
+
* @param {object} item - the (transitive) dep item being added
|
|
6937
|
+
* @param {object} parent - the dep item that requires `item`
|
|
6938
|
+
* @returns {void}
|
|
6939
|
+
*/
|
|
6940
|
+
_enforceRegistryDep(item, parent) {
|
|
6941
|
+
const violation = violatesRegistryPolicy(item);
|
|
6942
|
+
if (!violation) {
|
|
6943
|
+
return;
|
|
6944
|
+
}
|
|
6945
|
+
const depId = `${item.name}@${item.semver}`;
|
|
6946
|
+
let reason = `has an invalid/unparseable version "${violation.semver}"`;
|
|
6947
|
+
if (violation.kind === "url") {
|
|
6948
|
+
reason = `is from a non-registry source (${violation.urlType})`;
|
|
6949
|
+
} else if (violation.kind === "local") {
|
|
6950
|
+
reason = `is a local dependency declared below a non-registry source (${violation.urlType})`;
|
|
6951
|
+
}
|
|
6952
|
+
throw new Error(
|
|
6953
|
+
`fyn.enforceRegistryDeps: transitive dependency "${depId}" required by "${parent.id}" ${reason}. Only the top-level package.json may use git/github/URL dependencies - transitive dependencies must come from a registry.`
|
|
6954
|
+
);
|
|
6955
|
+
}
|
|
6429
6956
|
/**
|
|
6430
6957
|
* create the dep relation items for a package
|
|
6431
6958
|
*
|
|
@@ -6461,6 +6988,9 @@ class PkgDepResolver {
|
|
|
6461
6988
|
deepResolve
|
|
6462
6989
|
};
|
|
6463
6990
|
const newItem = new DepItem(opt, depItem);
|
|
6991
|
+
if (this._fyn.enforceRegistryDeps && depItem.depth >= 1) {
|
|
6992
|
+
this._enforceRegistryDep(newItem, depItem);
|
|
6993
|
+
}
|
|
6464
6994
|
if (noPrefetch !== true) this.prefetchMeta(newItem);
|
|
6465
6995
|
items.push(newItem);
|
|
6466
6996
|
}
|
|
@@ -6632,6 +7162,15 @@ class PkgDepResolver {
|
|
|
6632
7162
|
}
|
|
6633
7163
|
}
|
|
6634
7164
|
const metaJson = meta.versions[resolved];
|
|
7165
|
+
const localFromMeta = meta.local || metaJson.local;
|
|
7166
|
+
if (localFromMeta) {
|
|
7167
|
+
if (!item.localType) {
|
|
7168
|
+
item.localType = localFromMeta;
|
|
7169
|
+
}
|
|
7170
|
+
if (this._fyn.enforceRegistryDeps && item.parent.depth >= 1) {
|
|
7171
|
+
this._enforceRegistryDep(item, item.parent);
|
|
7172
|
+
}
|
|
7173
|
+
}
|
|
6635
7174
|
const platformCheck = () => {
|
|
6636
7175
|
const sysCheck2 = checkPkgOsCpu(metaJson);
|
|
6637
7176
|
if (sysCheck2 !== true) {
|
|
@@ -6688,11 +7227,7 @@ class PkgDepResolver {
|
|
|
6688
7227
|
pkgV.hasI = 1;
|
|
6689
7228
|
}
|
|
6690
7229
|
}
|
|
6691
|
-
const localFromMeta = meta.local || metaJson.local;
|
|
6692
7230
|
if (localFromMeta) {
|
|
6693
|
-
if (!item.localType) {
|
|
6694
|
-
item.localType = localFromMeta;
|
|
6695
|
-
}
|
|
6696
7231
|
pkgV.local = item.localType;
|
|
6697
7232
|
item.fullPath = pkgV.dir = pkgV.dist.fullPath;
|
|
6698
7233
|
pkgV.str = meta.jsonStr;
|
|
@@ -7166,9 +7701,9 @@ ${item.depPath.join(" > ")}`
|
|
|
7166
7701
|
throw new Error(failMetaMsg(item.name));
|
|
7167
7702
|
}
|
|
7168
7703
|
const updated = this._fyn.depLocker.update(item, meta);
|
|
7169
|
-
const
|
|
7170
|
-
if (
|
|
7171
|
-
return
|
|
7704
|
+
const resolved = this._resolveWithMeta({ item, meta: updated, force: false, noLocal: true });
|
|
7705
|
+
if (resolved) {
|
|
7706
|
+
return resolved;
|
|
7172
7707
|
}
|
|
7173
7708
|
logger.debug(
|
|
7174
7709
|
`cached meta for ${item.name} has no version satisfying ${item.semver}; refetching from registry`
|
|
@@ -7186,7 +7721,7 @@ ${item.depPath.join(" > ")}`
|
|
|
7186
7721
|
});
|
|
7187
7722
|
});
|
|
7188
7723
|
}).catch((err) => {
|
|
7189
|
-
if (item.dsrc
|
|
7724
|
+
if (!item.dsrc || !item.dsrc.includes("opt")) {
|
|
7190
7725
|
if (err.message.includes("Unable to retrieve meta")) {
|
|
7191
7726
|
throw err;
|
|
7192
7727
|
} else {
|
|
@@ -7244,7 +7779,13 @@ class PkgDistExtractor {
|
|
|
7244
7779
|
});
|
|
7245
7780
|
this._fyn = options.fyn;
|
|
7246
7781
|
this._promiseQ.on("done", (x) => this.done(x));
|
|
7247
|
-
this._promiseQ.on("failItem", (x) =>
|
|
7782
|
+
this._promiseQ.on("failItem", (x) => {
|
|
7783
|
+
logger.error("dist extractor failed item", x.error);
|
|
7784
|
+
const listener = _.get(x, "item.listener");
|
|
7785
|
+
if (listener) {
|
|
7786
|
+
setTimeout(() => listener.emit("fail", x.error), 0);
|
|
7787
|
+
}
|
|
7788
|
+
});
|
|
7248
7789
|
}
|
|
7249
7790
|
addPkgDist(data) {
|
|
7250
7791
|
this._promiseQ.addItem(data);
|
|
@@ -7302,6 +7843,10 @@ class PkgDistExtractor {
|
|
|
7302
7843
|
} else {
|
|
7303
7844
|
const json = await this._fyn.ensureProperPkgDir(pkg, fullOutDir);
|
|
7304
7845
|
if (json) {
|
|
7846
|
+
if (data.listener) {
|
|
7847
|
+
const listener = data.listener;
|
|
7848
|
+
setTimeout(() => listener.emit("done", json), 0);
|
|
7849
|
+
}
|
|
7305
7850
|
return json;
|
|
7306
7851
|
}
|
|
7307
7852
|
await this._fyn.createPkgOutDir(fullOutDir);
|
|
@@ -7509,6 +8054,7 @@ class PkgDistFetcher {
|
|
|
7509
8054
|
}
|
|
7510
8055
|
/**
|
|
7511
8056
|
* Check if pkg already has a copy extracted to node_modules
|
|
8057
|
+
*
|
|
7512
8058
|
* @param {*} pkg - package info
|
|
7513
8059
|
* @returns {*} pkg in FV_DIR and its package.json
|
|
7514
8060
|
*/
|
|
@@ -7591,8 +8137,14 @@ const logger = __webpack_require__("./lib/logger.ts");
|
|
|
7591
8137
|
const logFormat = __webpack_require__("./lib/util/log-format.ts");
|
|
7592
8138
|
const fynTil = __webpack_require__("./lib/util/fyntil.ts");
|
|
7593
8139
|
const hardLinkDir = __webpack_require__("./lib/util/hard-link-dir.ts");
|
|
8140
|
+
const {
|
|
8141
|
+
makeLocalExportsManifest,
|
|
8142
|
+
reconcileLocalExports,
|
|
8143
|
+
resolveLocalExportsConfig
|
|
8144
|
+
} = __webpack_require__("./lib/local-exports.ts");
|
|
7594
8145
|
const { INSTALL_PACKAGE } = __webpack_require__("./lib/log-items.ts");
|
|
7595
8146
|
const { runNpmScript } = __webpack_require__("./lib/util/run-npm-script.ts");
|
|
8147
|
+
const { evaluateScriptPolicy, isScriptAllowed } = __webpack_require__("./lib/util/lifecycle-script-policy.ts");
|
|
7596
8148
|
const xaa = __webpack_require__("./lib/util/xaa.ts");
|
|
7597
8149
|
const { AggregateError } = __webpack_require__("./node_modules/.f/_/@jchip/error/1.0.3/@jchip/error/dist/index.js");
|
|
7598
8150
|
const { RESOLVE_ORDER, RSEMVERS, LOCK_RSEMVERS, SEMVER } = __webpack_require__("./lib/symbols.ts");
|
|
@@ -7674,7 +8226,7 @@ class PkgInstaller {
|
|
|
7674
8226
|
} catch (err) {
|
|
7675
8227
|
if (err.code === "EPERM") {
|
|
7676
8228
|
const st = await Fs.stat(pkgJsonFp);
|
|
7677
|
-
await Fs.chmod(pkgJsonFp, st.mode
|
|
8229
|
+
await Fs.chmod(pkgJsonFp, st.mode | 384);
|
|
7678
8230
|
await Fs.writeFile(pkgJsonFp, `${outputStr}
|
|
7679
8231
|
`);
|
|
7680
8232
|
}
|
|
@@ -7746,7 +8298,7 @@ class PkgInstaller {
|
|
|
7746
8298
|
if (depInfo._removing) return;
|
|
7747
8299
|
depInfo._removing = true;
|
|
7748
8300
|
const optReqs = depInfo.requests.map((req) => {
|
|
7749
|
-
return req.reverse().find((r) => r.startsWith("opt"));
|
|
8301
|
+
return req.slice().reverse().find((r) => r.startsWith("opt"));
|
|
7750
8302
|
});
|
|
7751
8303
|
const failedId = `${depInfo.name}@${depInfo.version}`;
|
|
7752
8304
|
for (const r of optReqs) {
|
|
@@ -7869,12 +8421,27 @@ class PkgInstaller {
|
|
|
7869
8421
|
if (this._fyn.showDeprecated && _.isEmpty(warned)) {
|
|
7870
8422
|
logger.info(chalk.green("HOORAY!!! None of your dependencies are marked deprecated."));
|
|
7871
8423
|
}
|
|
7872
|
-
}).then(() => this._saveLockData()).then(() => {
|
|
8424
|
+
}).then(() => this._installLocalExports()).then(() => this._saveLockData()).then(() => {
|
|
7873
8425
|
logger.info(`${chalk.green("done install")} ${logFormat.time(Date.now() - start)}`);
|
|
7874
8426
|
}).finally(() => {
|
|
7875
8427
|
logger.removeItem(INSTALL_PACKAGE);
|
|
7876
8428
|
});
|
|
7877
8429
|
}
|
|
8430
|
+
async _installLocalExports() {
|
|
8431
|
+
const pkgsData = this._data.getPkgsData();
|
|
8432
|
+
const config = resolveLocalExportsConfig(this._fyn._pkg);
|
|
8433
|
+
const manifest = await makeLocalExportsManifest({
|
|
8434
|
+
cwd: this._fyn._cwd,
|
|
8435
|
+
config,
|
|
8436
|
+
depInfos: this.toLink.filter((depInfo) => {
|
|
8437
|
+
const versions = pkgsData[depInfo.name];
|
|
8438
|
+
return versions && versions[depInfo.version] === depInfo;
|
|
8439
|
+
})
|
|
8440
|
+
});
|
|
8441
|
+
const previous = this._fyn._installConfig.localExports;
|
|
8442
|
+
await reconcileLocalExports({ cwd: this._fyn._cwd, manifest, previous });
|
|
8443
|
+
this._fyn.setLocalExports(manifest);
|
|
8444
|
+
}
|
|
7878
8445
|
async _buildLocalPkg(depInfo) {
|
|
7879
8446
|
if (this._fyn._options.buildLocal && this._fyn._localPkgBuilder) {
|
|
7880
8447
|
const itemRes = await this._fyn._localPkgBuilder.waitForItem(depInfo.dir);
|
|
@@ -7906,25 +8473,60 @@ class PkgInstaller {
|
|
|
7906
8473
|
}
|
|
7907
8474
|
json._fyn = {};
|
|
7908
8475
|
const scripts = json.scripts || {};
|
|
8476
|
+
const scriptPolicy = evaluateScriptPolicy(depInfo, this._fyn.allowScripts, {
|
|
8477
|
+
allowTopLevel: this._fyn.allowTopLevelScripts
|
|
8478
|
+
});
|
|
8479
|
+
const blockedScripts = [];
|
|
8480
|
+
const isAllowed = (scriptName) => {
|
|
8481
|
+
if (isScriptAllowed(scriptPolicy, scriptName)) {
|
|
8482
|
+
return true;
|
|
8483
|
+
}
|
|
8484
|
+
blockedScripts.push(scriptName);
|
|
8485
|
+
return false;
|
|
8486
|
+
};
|
|
7909
8487
|
const hasPI = json.hasPI || Boolean(scripts.preinstall);
|
|
7910
8488
|
const piExed = Boolean(depInfo.preinstall);
|
|
7911
8489
|
if (!piExed && hasPI) {
|
|
7912
8490
|
if (depInfo.preInstalled) {
|
|
7913
8491
|
json._fyn.preinstall = true;
|
|
7914
|
-
} else {
|
|
8492
|
+
} else if (isAllowed("preinstall")) {
|
|
7915
8493
|
logger.debug("adding preinstall step for", depInfo.dir);
|
|
7916
8494
|
this.preInstall.push(depInfo);
|
|
7917
8495
|
}
|
|
7918
8496
|
}
|
|
7919
8497
|
this.toLink.push(depInfo);
|
|
7920
8498
|
const install = ["install", "postinstall"].filter((x) => {
|
|
7921
|
-
return Boolean(scripts[x]) && !json._fyn[x];
|
|
8499
|
+
return Boolean(scripts[x]) && !json._fyn[x] && isAllowed(x);
|
|
7922
8500
|
});
|
|
7923
8501
|
if (install.length > 0) {
|
|
7924
8502
|
logger.debug("adding install step for", depInfo.dir, install);
|
|
7925
8503
|
depInfo.install = install;
|
|
7926
8504
|
this.postInstall.push(depInfo);
|
|
7927
8505
|
}
|
|
8506
|
+
if (blockedScripts.length > 0) {
|
|
8507
|
+
this._warnBlockedScripts(depInfo, scriptPolicy, blockedScripts);
|
|
8508
|
+
}
|
|
8509
|
+
}
|
|
8510
|
+
_warnBlockedScripts(depInfo, policy, blocked) {
|
|
8511
|
+
const id = logFormat.pkgId(depInfo);
|
|
8512
|
+
logger.warn(
|
|
8513
|
+
`${chalk.black.bgYellow("WARN")} ${chalk.magenta("scripts blocked")} ${id}`,
|
|
8514
|
+
chalk.yellow(
|
|
8515
|
+
`skipped lifecycle [${blocked.join(", ")}] for non-registry (${policy.urlType}) package - not in fyn.allowScripts`
|
|
8516
|
+
)
|
|
8517
|
+
);
|
|
8518
|
+
logger.verbose(
|
|
8519
|
+
chalk.blue(" To allow, add to package.json:"),
|
|
8520
|
+
chalk.cyan(
|
|
8521
|
+
`"fyn": { "allowScripts": { "${policy.key}": [${blocked.map((s) => `"${s}"`).join(", ")}] } }`
|
|
8522
|
+
)
|
|
8523
|
+
);
|
|
8524
|
+
if (policy.topLevel) {
|
|
8525
|
+
logger.verbose(
|
|
8526
|
+
chalk.blue(" Or trust all direct deps' scripts with:"),
|
|
8527
|
+
chalk.cyan(`"fyn": { "allowTopLevelScripts": true }`)
|
|
8528
|
+
);
|
|
8529
|
+
}
|
|
7928
8530
|
}
|
|
7929
8531
|
_cleanBin() {
|
|
7930
8532
|
logger.updateItem(INSTALL_PACKAGE, "cleaning node_modules/.bin");
|
|
@@ -8126,6 +8728,8 @@ const PkgDepLinker = __webpack_require__("./lib/pkg-dep-linker.ts");
|
|
|
8126
8728
|
const semverUtil = __webpack_require__("./lib/util/semver.ts");
|
|
8127
8729
|
const { readPkgJson } = __webpack_require__("./lib/util/fyntil.ts");
|
|
8128
8730
|
const { OPTIONAL_RESOLVER } = __webpack_require__("./lib/log-items.ts");
|
|
8731
|
+
const { DEP_ITEM, SEMVER } = __webpack_require__("./lib/symbols.ts");
|
|
8732
|
+
const { evaluateScriptPolicy, isScriptAllowed } = __webpack_require__("./lib/util/lifecycle-script-policy.ts");
|
|
8129
8733
|
xsh.Promise = Promise;
|
|
8130
8734
|
class PkgOptResolver {
|
|
8131
8735
|
constructor(options) {
|
|
@@ -8188,6 +8792,32 @@ class PkgOptResolver {
|
|
|
8188
8792
|
// - 0: add item back to resolve
|
|
8189
8793
|
// - not: add item to queue for logging at end
|
|
8190
8794
|
//
|
|
8795
|
+
/**
|
|
8796
|
+
* Evaluate the lifecycle-script policy for an optional dep's preinstall.
|
|
8797
|
+
*
|
|
8798
|
+
* Non-registry (github/git/url) optional deps do not run preinstall unless
|
|
8799
|
+
* whitelisted via `fyn.allowScripts` / `fyn.allowTopLevelScripts` - the same
|
|
8800
|
+
* deny-by-default policy the regular installer enforces (FPM-41). Registry
|
|
8801
|
+
* and local deps are trusted and always allowed.
|
|
8802
|
+
*
|
|
8803
|
+
* @param {object} item the optional dep's DepItem
|
|
8804
|
+
* @param {string} name package name
|
|
8805
|
+
* @param {string} version resolved version
|
|
8806
|
+
* @returns {{allowed:boolean, policy:object}} the policy decision
|
|
8807
|
+
*/
|
|
8808
|
+
checkPreinstallPolicy(item, name, version) {
|
|
8809
|
+
const optDepInfo = {
|
|
8810
|
+
[DEP_ITEM]: item,
|
|
8811
|
+
[SEMVER]: item.semver,
|
|
8812
|
+
name,
|
|
8813
|
+
version,
|
|
8814
|
+
top: !_.get(item, ["parent", "depth"])
|
|
8815
|
+
};
|
|
8816
|
+
const policy = evaluateScriptPolicy(optDepInfo, this._fyn.allowScripts, {
|
|
8817
|
+
allowTopLevel: this._fyn.allowTopLevelScripts
|
|
8818
|
+
});
|
|
8819
|
+
return { allowed: isScriptAllowed(policy, "preinstall"), policy };
|
|
8820
|
+
}
|
|
8191
8821
|
/* eslint-disable max-statements */
|
|
8192
8822
|
optCheck(data) {
|
|
8193
8823
|
const name = data.item.name;
|
|
@@ -8306,6 +8936,17 @@ class PkgOptResolver {
|
|
|
8306
8936
|
);
|
|
8307
8937
|
return { passed: true };
|
|
8308
8938
|
} else if (_.get(res, "pkg.scripts.preinstall")) {
|
|
8939
|
+
const { allowed, policy } = this.checkPreinstallPolicy(data.item, name, version);
|
|
8940
|
+
if (!allowed) {
|
|
8941
|
+
logger.warn(
|
|
8942
|
+
`${chalk.black.bgYellow("WARN")} ${chalk.magenta("scripts blocked")} ${displayId}`,
|
|
8943
|
+
chalk.yellow(
|
|
8944
|
+
`skipped optional preinstall for non-registry (${policy.urlType}) package - not in fyn.allowScripts`
|
|
8945
|
+
)
|
|
8946
|
+
);
|
|
8947
|
+
logPass("preinstall blocked by script policy - keeping optional package");
|
|
8948
|
+
return { passed: true };
|
|
8949
|
+
}
|
|
8309
8950
|
data.runningScript = true;
|
|
8310
8951
|
logger.updateItem(OPTIONAL_RESOLVER, `running preinstall for ${displayId}`);
|
|
8311
8952
|
const ls = new LifecycleScripts({
|
|
@@ -8404,12 +9045,19 @@ const { PackageRef } = __webpack_require__("./node_modules/.f/_/@fynpo/base/1.1.
|
|
|
8404
9045
|
const Arborist = __webpack_require__("./node_modules/.f/_/@npmcli/arborist/9.1.6/@npmcli/arborist/lib/index.js");
|
|
8405
9046
|
const WATCH_TIME = 5e3;
|
|
8406
9047
|
const META_CACHE_STALE_TIME = 24 * 60 * 60 * 1e3;
|
|
9048
|
+
const SAFE_GIT_TOKEN = /^[A-Za-z0-9._/~^-]+$/;
|
|
9049
|
+
function isSafeGitToken(s) {
|
|
9050
|
+
return typeof s === "string" && s.length > 0 && s.length < 256 && SAFE_GIT_TOKEN.test(s) && !s.startsWith("-");
|
|
9051
|
+
}
|
|
9052
|
+
function isPinnedGitCommit(semver) {
|
|
9053
|
+
if (!semver) return false;
|
|
9054
|
+
const committish = semver.includes("#") ? semver.split("#")[1] : semver;
|
|
9055
|
+
return /^[a-f0-9]{40}$/.test(committish);
|
|
9056
|
+
}
|
|
8407
9057
|
async function checkGitRepoHasNewCommits(gitUrl, ref, cachedCommitHash) {
|
|
8408
9058
|
if (!cachedCommitHash) return true;
|
|
8409
9059
|
try {
|
|
8410
|
-
const {
|
|
8411
|
-
const Path2 = __webpack_require__("path");
|
|
8412
|
-
const fs2 = __webpack_require__("fs");
|
|
9060
|
+
const { execFileSync } = __webpack_require__("child_process");
|
|
8413
9061
|
let actualGitUrl = gitUrl;
|
|
8414
9062
|
let isLocalRepo = false;
|
|
8415
9063
|
let localRepoPath = null;
|
|
@@ -8421,10 +9069,15 @@ async function checkGitRepoHasNewCommits(gitUrl, ref, cachedCommitHash) {
|
|
|
8421
9069
|
}
|
|
8422
9070
|
} else if (!gitUrl.includes("://")) {
|
|
8423
9071
|
isLocalRepo = true;
|
|
8424
|
-
localRepoPath =
|
|
9072
|
+
localRepoPath = Path.resolve(gitUrl);
|
|
8425
9073
|
}
|
|
8426
9074
|
if (isLocalRepo && localRepoPath) {
|
|
8427
|
-
const
|
|
9075
|
+
const safeRef = ref || "HEAD";
|
|
9076
|
+
if (!isSafeGitToken(safeRef)) {
|
|
9077
|
+
logger.debug(`refusing potentially unsafe git ref: ${safeRef}`);
|
|
9078
|
+
return null;
|
|
9079
|
+
}
|
|
9080
|
+
const output = execFileSync("git", ["rev-parse", safeRef], {
|
|
8428
9081
|
cwd: localRepoPath,
|
|
8429
9082
|
stdio: "pipe",
|
|
8430
9083
|
encoding: "utf8",
|
|
@@ -8447,7 +9100,12 @@ async function checkGitRepoHasNewCommits(gitUrl, ref, cachedCommitHash) {
|
|
|
8447
9100
|
} else {
|
|
8448
9101
|
actualGitUrl = gitUrl;
|
|
8449
9102
|
}
|
|
8450
|
-
const
|
|
9103
|
+
const safeRef = ref || "HEAD";
|
|
9104
|
+
if (!isSafeGitToken(safeRef) || actualGitUrl.startsWith("-")) {
|
|
9105
|
+
logger.debug(`refusing potentially unsafe git url/ref: ${actualGitUrl}#${safeRef}`);
|
|
9106
|
+
return null;
|
|
9107
|
+
}
|
|
9108
|
+
const output = execFileSync("git", ["ls-remote", actualGitUrl, safeRef], {
|
|
8451
9109
|
stdio: "pipe",
|
|
8452
9110
|
encoding: "utf8",
|
|
8453
9111
|
timeout: 1e4
|
|
@@ -8684,16 +9342,17 @@ class PkgSrcManager {
|
|
|
8684
9342
|
logger.debug(`pacote.packument ${qItem.packumentUrl}`);
|
|
8685
9343
|
const promise2 = pacote.packument(
|
|
8686
9344
|
pkgName,
|
|
9345
|
+
// pacote 21 / npm-registry-fetch 19 read camelCase options; the old
|
|
9346
|
+
// kebab-case names were silently ignored. preferOnline forces a server
|
|
9347
|
+
// revalidation (cache mode "no-cache") for this refresh path.
|
|
8687
9348
|
this.getPacoteOpts({
|
|
8688
|
-
|
|
8689
|
-
|
|
8690
|
-
|
|
8691
|
-
"cache-key": qItem.cacheKey,
|
|
9349
|
+
fullMetadata: true,
|
|
9350
|
+
fetchRetries: 3,
|
|
9351
|
+
preferOnline: true,
|
|
8692
9352
|
memoize: false
|
|
8693
9353
|
})
|
|
8694
9354
|
);
|
|
8695
9355
|
return promise2.then((x) => {
|
|
8696
|
-
this._metaStat.inTx--;
|
|
8697
9356
|
if (!x) {
|
|
8698
9357
|
const msg = `pacote returned null/undefined for packument of ${pkgName}`;
|
|
8699
9358
|
logger.error(chalk.yellow(msg));
|
|
@@ -8714,6 +9373,7 @@ class PkgSrcManager {
|
|
|
8714
9373
|
this.updateFetchMetaStatus(false);
|
|
8715
9374
|
const promise = qItem.item.urlType ? this.fetchUrlSemverMeta(qItem.item) : pacoteRequest();
|
|
8716
9375
|
return promise.then((x) => {
|
|
9376
|
+
this._metaStat.inTx--;
|
|
8717
9377
|
const time = Date.now() - startTime;
|
|
8718
9378
|
if (time > 20 * 1e3) {
|
|
8719
9379
|
logger.info(
|
|
@@ -8728,10 +9388,11 @@ class PkgSrcManager {
|
|
|
8728
9388
|
qItem.defer.reject(new AggregateError([new Error(msg)], msg));
|
|
8729
9389
|
return;
|
|
8730
9390
|
}
|
|
8731
|
-
refreshCacheEntry(this.
|
|
9391
|
+
refreshCacheEntry(this._cacheDir, qItem.cacheKey).catch(() => {
|
|
8732
9392
|
});
|
|
8733
9393
|
qItem.defer.resolve(x);
|
|
8734
9394
|
}).catch((err) => {
|
|
9395
|
+
this._metaStat.inTx--;
|
|
8735
9396
|
qItem.defer.reject(err);
|
|
8736
9397
|
});
|
|
8737
9398
|
}
|
|
@@ -8773,19 +9434,7 @@ class PkgSrcManager {
|
|
|
8773
9434
|
} else {
|
|
8774
9435
|
dirPacker = this._getPacoteDirPacker();
|
|
8775
9436
|
}
|
|
8776
|
-
|
|
8777
|
-
if (item.urlType.startsWith("git") && item.semver && !item.semver.match(/^[a-f0-9]{40}$/)) {
|
|
8778
|
-
const potentialCacheKeys = [
|
|
8779
|
-
// Try common cache key patterns based on semver
|
|
8780
|
-
`fyn-tarball-for-git+https://github.com/${item.semver.replace(/^github:/, "").split("#")[0]}.git#`,
|
|
8781
|
-
`fyn-tarball-for-git+ssh://git@github.com/${item.semver.replace(/^github:/, "").split("#")[0]}.git#`
|
|
8782
|
-
];
|
|
8783
|
-
for (const baseKey of potentialCacheKeys) {
|
|
8784
|
-
try {
|
|
8785
|
-
} catch (e) {
|
|
8786
|
-
}
|
|
8787
|
-
}
|
|
8788
|
-
}
|
|
9437
|
+
const pacoteOpts = { dirPacker };
|
|
8789
9438
|
return pacote.manifest(`${item.name}@${item.semver}`, this.getPacoteOpts(pacoteOpts)).then((manifest) => {
|
|
8790
9439
|
manifest = Object.assign({}, manifest);
|
|
8791
9440
|
return {
|
|
@@ -8809,9 +9458,10 @@ class PkgSrcManager {
|
|
|
8809
9458
|
let integrity;
|
|
8810
9459
|
let shouldRefresh = false;
|
|
8811
9460
|
if (tgzCacheInfo) {
|
|
8812
|
-
const
|
|
9461
|
+
const cachedTarball = tgzCacheInfo.metadata?.dist?.tarball;
|
|
9462
|
+
const cachedResolved = tgzCacheInfo.metadata?._resolved || (cachedTarball?.startsWith(MARK_URL_SPEC) ? JSON.parse(cachedTarball.slice(MARK_URL_SPEC.length))._resolved : null);
|
|
8813
9463
|
const cachedCommitHash = cachedResolved?.match(/#([a-f0-9]{40})$/)?.[1];
|
|
8814
|
-
if (!shouldRefresh && cachedCommitHash && item.semver && !item.semver
|
|
9464
|
+
if (!shouldRefresh && cachedCommitHash && item.semver && !isPinnedGitCommit(item.semver)) {
|
|
8815
9465
|
let gitUrl = item.semver;
|
|
8816
9466
|
let ref = "HEAD";
|
|
8817
9467
|
if (gitUrl.includes("#")) {
|
|
@@ -8834,17 +9484,15 @@ class PkgSrcManager {
|
|
|
8834
9484
|
logger.debug(
|
|
8835
9485
|
`git cache for '${item.name}' has new commits (cached: ${cachedCommitHash.substring(0, 8)}, checking ${ref}), forcing refresh`
|
|
8836
9486
|
);
|
|
8837
|
-
} else {
|
|
8838
|
-
|
|
8839
|
-
|
|
8840
|
-
|
|
8841
|
-
|
|
8842
|
-
|
|
8843
|
-
|
|
8844
|
-
|
|
8845
|
-
|
|
8846
|
-
);
|
|
8847
|
-
}
|
|
9487
|
+
} else if (tgzCacheInfo.refreshTime) {
|
|
9488
|
+
const stale = Date.now() - tgzCacheInfo.refreshTime;
|
|
9489
|
+
const staleByTime = stale >= META_CACHE_STALE_TIME;
|
|
9490
|
+
if (staleByTime) {
|
|
9491
|
+
shouldRefresh = true;
|
|
9492
|
+
const reason = hasNewCommits === null ? "ls-remote failed" : "no new commits";
|
|
9493
|
+
logger.debug(
|
|
9494
|
+
`git cache for '${item.name}' (${reason}), cache is stale by time (${(stale / 1e3 / 60 / 60).toFixed(1)}h old), forcing refresh`
|
|
9495
|
+
);
|
|
8848
9496
|
}
|
|
8849
9497
|
}
|
|
8850
9498
|
} else if (!shouldRefresh && tgzCacheInfo.refreshTime) {
|
|
@@ -8918,6 +9566,7 @@ class PkgSrcManager {
|
|
|
8918
9566
|
const cacheKey = `make-fetch-happen:request-cache:${packumentUrl}`;
|
|
8919
9567
|
const legacyCacheKey = `make-fetch-happen:request-cache:full:${packumentUrl}`;
|
|
8920
9568
|
const cacheKeys = [cacheKey, legacyCacheKey];
|
|
9569
|
+
let cacheMemoized = false;
|
|
8921
9570
|
const loadCachedPackument = async (key, memoize = true) => {
|
|
8922
9571
|
try {
|
|
8923
9572
|
const cached = await cacache.get(this._cacheDir, key, { memoize });
|
|
@@ -8940,6 +9589,33 @@ class PkgSrcManager {
|
|
|
8940
9589
|
}
|
|
8941
9590
|
return _.maxBy(cachedEntries, (cached) => cached.refreshTime || 0) || cachedEntries[0];
|
|
8942
9591
|
};
|
|
9592
|
+
const loadPreparedUrlMeta = async () => {
|
|
9593
|
+
const info = await getCacheInfoWithRefreshTime(
|
|
9594
|
+
this._cacheDir,
|
|
9595
|
+
`fyn-tarball-for-${item.semver}`
|
|
9596
|
+
);
|
|
9597
|
+
const cachedManifest = info && info.metadata;
|
|
9598
|
+
if (!(cachedManifest && cachedManifest.version)) {
|
|
9599
|
+
return void 0;
|
|
9600
|
+
}
|
|
9601
|
+
const tarball = JSON.stringify(
|
|
9602
|
+
Object.assign(
|
|
9603
|
+
_.pick(item, ["urlType", "semver"]),
|
|
9604
|
+
_.pick(cachedManifest, ["_resolved", "_id"])
|
|
9605
|
+
)
|
|
9606
|
+
);
|
|
9607
|
+
const manifest = Object.assign({}, cachedManifest, {
|
|
9608
|
+
dist: {
|
|
9609
|
+
integrity: info.integrity,
|
|
9610
|
+
tarball: `${MARK_URL_SPEC}${tarball}`
|
|
9611
|
+
}
|
|
9612
|
+
});
|
|
9613
|
+
return {
|
|
9614
|
+
name: item.name,
|
|
9615
|
+
versions: { [manifest.version]: manifest },
|
|
9616
|
+
urlVersions: { [item.semver]: manifest }
|
|
9617
|
+
};
|
|
9618
|
+
};
|
|
8943
9619
|
const readMemoizedPackument = async () => {
|
|
8944
9620
|
const memoized = await loadBestCachedPackument(false);
|
|
8945
9621
|
if (!(memoized && memoized.data)) {
|
|
@@ -8950,7 +9626,11 @@ class PkgSrcManager {
|
|
|
8950
9626
|
this._metaStat.wait--;
|
|
8951
9627
|
return JSON.parse(memoized.data.toString());
|
|
8952
9628
|
};
|
|
9629
|
+
let fetchAttempted = false;
|
|
9630
|
+
let foundCache;
|
|
9631
|
+
let foundPackument;
|
|
8953
9632
|
const queueMetaFetchRequest = (cached) => {
|
|
9633
|
+
fetchAttempted = true;
|
|
8954
9634
|
const offline = this._fyn.remoteMetaDisabled;
|
|
8955
9635
|
if (cached && this._fyn.forceCache) {
|
|
8956
9636
|
this._metaStat.wait--;
|
|
@@ -8975,18 +9655,24 @@ class PkgSrcManager {
|
|
|
8975
9655
|
return netQItem.defer.promise;
|
|
8976
9656
|
};
|
|
8977
9657
|
this._metaStat.wait++;
|
|
8978
|
-
let foundCache;
|
|
8979
|
-
let cacheMemoized = false;
|
|
8980
9658
|
const metaMemoizeUrl = this._fyn._options.metaMemoize;
|
|
8981
|
-
|
|
8982
|
-
|
|
8983
|
-
|
|
8984
|
-
|
|
8985
|
-
|
|
8986
|
-
|
|
8987
|
-
|
|
8988
|
-
|
|
9659
|
+
let cacheLookup;
|
|
9660
|
+
if (item.urlType) {
|
|
9661
|
+
cacheLookup = this._fyn.remoteMetaDisabled ? loadPreparedUrlMeta().then((preparedUrlMeta) => ({ preparedUrlMeta })) : Promise.resolve();
|
|
9662
|
+
} else if (forceRefresh) {
|
|
9663
|
+
cacheLookup = Promise.resolve();
|
|
9664
|
+
} else {
|
|
9665
|
+
cacheLookup = loadBestCachedPackument(true);
|
|
9666
|
+
}
|
|
9667
|
+
const promise = cacheLookup.then((cached) => {
|
|
9668
|
+
if (cached && cached.preparedUrlMeta) {
|
|
9669
|
+
cacheMemoized = true;
|
|
9670
|
+
this._metaStat.wait--;
|
|
9671
|
+
return cached.preparedUrlMeta;
|
|
9672
|
+
}
|
|
8989
9673
|
foundCache = cached;
|
|
9674
|
+
const packument = cached && cached.data && JSON.parse(cached.data);
|
|
9675
|
+
foundPackument = packument;
|
|
8990
9676
|
if (cached && cached.refreshTime) {
|
|
8991
9677
|
const stale = Date.now() - cached.refreshTime;
|
|
8992
9678
|
const since = (stale / 1e3).toFixed(2);
|
|
@@ -9029,10 +9715,19 @@ class PkgSrcManager {
|
|
|
9029
9715
|
return queueMetaFetchRequest(packument);
|
|
9030
9716
|
}
|
|
9031
9717
|
}).catch((err) => {
|
|
9718
|
+
if (fetchAttempted) {
|
|
9719
|
+
if (foundPackument) {
|
|
9720
|
+
cacheMemoized = true;
|
|
9721
|
+
logger.warn(
|
|
9722
|
+
`failed to refresh packument for '${pkgName}', using stale cached metadata: ${err.message}`
|
|
9723
|
+
);
|
|
9724
|
+
return foundPackument;
|
|
9725
|
+
}
|
|
9726
|
+
throw err;
|
|
9727
|
+
}
|
|
9032
9728
|
if (foundCache) {
|
|
9033
9729
|
const data = foundCache.data && foundCache.data.toString();
|
|
9034
9730
|
logger.debug(`fail to process packument cache - ${err.message}; data ${data}`);
|
|
9035
|
-
throw err;
|
|
9036
9731
|
}
|
|
9037
9732
|
return queueMetaFetchRequest();
|
|
9038
9733
|
}).then((meta) => {
|
|
@@ -9096,7 +9791,7 @@ class PkgSrcManager {
|
|
|
9096
9791
|
return passthrough2;
|
|
9097
9792
|
}
|
|
9098
9793
|
const opts = this.getPacoteOpts({
|
|
9099
|
-
|
|
9794
|
+
fullMetadata: true,
|
|
9100
9795
|
integrity,
|
|
9101
9796
|
resolved: tarballUrl
|
|
9102
9797
|
});
|
|
@@ -9213,6 +9908,7 @@ class PkgSrcManager {
|
|
|
9213
9908
|
}
|
|
9214
9909
|
module.exports = PkgSrcManager;
|
|
9215
9910
|
module.exports.META_CACHE_STALE_TIME = META_CACHE_STALE_TIME;
|
|
9911
|
+
module.exports.isPinnedGitCommit = isPinnedGitCommit;
|
|
9216
9912
|
|
|
9217
9913
|
|
|
9218
9914
|
/***/ }),
|
|
@@ -9325,7 +10021,8 @@ async function checkPkgNeedInstall(dir, checkCtime = 0) {
|
|
|
9325
10021
|
hasScript
|
|
9326
10022
|
};
|
|
9327
10023
|
} catch (error) {
|
|
9328
|
-
|
|
10024
|
+
logger.warn(`unable to determine if local package at ${dir} needs install: ${error.message}`);
|
|
10025
|
+
throw error;
|
|
9329
10026
|
}
|
|
9330
10027
|
}
|
|
9331
10028
|
exports.checkPkgNeedInstall = checkPkgNeedInstall;
|
|
@@ -9532,7 +10229,10 @@ const fyntil = {
|
|
|
9532
10229
|
return rmObj;
|
|
9533
10230
|
},
|
|
9534
10231
|
exit(err) {
|
|
9535
|
-
|
|
10232
|
+
if (typeof err === "number") {
|
|
10233
|
+
return process.exit(err);
|
|
10234
|
+
}
|
|
10235
|
+
return process.exit(err ? 1 : 0);
|
|
9536
10236
|
},
|
|
9537
10237
|
async readJson(file, defaultData) {
|
|
9538
10238
|
try {
|
|
@@ -9926,7 +10626,7 @@ async function linkPackTree({ tree, src, dest, sym1, sourceMaps }) {
|
|
|
9926
10626
|
const files = tree[SYM_FILES];
|
|
9927
10627
|
const destFiles = await prepDestDir(dest);
|
|
9928
10628
|
for (const file of files) {
|
|
9929
|
-
if (!ci.isCI && file.match(
|
|
10629
|
+
if (!ci.isCI && file.match(/\.(js|mjs)\.map$/)) {
|
|
9930
10630
|
continue;
|
|
9931
10631
|
}
|
|
9932
10632
|
destFiles[file] = true;
|
|
@@ -9987,6 +10687,133 @@ module.exports = {
|
|
|
9987
10687
|
module.exports = __webpack_require__("./node_modules/.f/_/item-queue/1.1.2/item-queue/lib/inflight.js");
|
|
9988
10688
|
|
|
9989
10689
|
|
|
10690
|
+
/***/ }),
|
|
10691
|
+
|
|
10692
|
+
/***/ "./lib/util/lifecycle-script-policy.ts":
|
|
10693
|
+
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
|
|
10694
|
+
|
|
10695
|
+
"use strict";
|
|
10696
|
+
|
|
10697
|
+
const semverUtil = __webpack_require__("./lib/util/semver.ts");
|
|
10698
|
+
const { DEP_ITEM, SEMVER } = __webpack_require__("./lib/symbols.ts");
|
|
10699
|
+
const TRUSTED_URL_TYPES = /* @__PURE__ */ new Set(["npm"]);
|
|
10700
|
+
function getSourceUrlType(depItem) {
|
|
10701
|
+
let item = depItem;
|
|
10702
|
+
while (item) {
|
|
10703
|
+
const analyzed = item.semver ? semverUtil.analyze(item.semver) : {};
|
|
10704
|
+
const urlType = item.urlType || analyzed.urlType;
|
|
10705
|
+
if (urlType) {
|
|
10706
|
+
return urlType;
|
|
10707
|
+
}
|
|
10708
|
+
if (!(item.localType || analyzed.localType)) {
|
|
10709
|
+
return void 0;
|
|
10710
|
+
}
|
|
10711
|
+
item = item.parent;
|
|
10712
|
+
}
|
|
10713
|
+
return void 0;
|
|
10714
|
+
}
|
|
10715
|
+
function getUrlType(depInfo) {
|
|
10716
|
+
const depItem = depInfo[DEP_ITEM];
|
|
10717
|
+
if (depItem) {
|
|
10718
|
+
return getSourceUrlType(depItem);
|
|
10719
|
+
}
|
|
10720
|
+
const spec = depInfo[SEMVER];
|
|
10721
|
+
if (spec) {
|
|
10722
|
+
return semverUtil.analyze(spec).urlType;
|
|
10723
|
+
}
|
|
10724
|
+
return void 0;
|
|
10725
|
+
}
|
|
10726
|
+
function isTrustedScriptSource(depInfo) {
|
|
10727
|
+
const urlType = getUrlType(depInfo);
|
|
10728
|
+
return !urlType || TRUSTED_URL_TYPES.has(urlType);
|
|
10729
|
+
}
|
|
10730
|
+
function makeAllowKeys(depInfo) {
|
|
10731
|
+
const depItem = depInfo[DEP_ITEM];
|
|
10732
|
+
const spec = depItem && depItem.semver || depInfo[SEMVER];
|
|
10733
|
+
const keys = [];
|
|
10734
|
+
if (spec) {
|
|
10735
|
+
keys.push(`${depInfo.name}@${spec}`);
|
|
10736
|
+
}
|
|
10737
|
+
if (depInfo.version && depInfo.version !== spec) {
|
|
10738
|
+
keys.push(`${depInfo.name}@${depInfo.version}`);
|
|
10739
|
+
}
|
|
10740
|
+
return keys;
|
|
10741
|
+
}
|
|
10742
|
+
function normalizeAllowEntry(value, acc) {
|
|
10743
|
+
if (value === true || value === "*") {
|
|
10744
|
+
acc.allowAll = true;
|
|
10745
|
+
return acc;
|
|
10746
|
+
}
|
|
10747
|
+
let list = [];
|
|
10748
|
+
if (Array.isArray(value)) {
|
|
10749
|
+
list = value;
|
|
10750
|
+
} else if (value !== void 0) {
|
|
10751
|
+
list = [value];
|
|
10752
|
+
}
|
|
10753
|
+
for (const s of list) {
|
|
10754
|
+
if (s === true || s === "*") {
|
|
10755
|
+
acc.allowAll = true;
|
|
10756
|
+
} else if (typeof s === "string") {
|
|
10757
|
+
acc.scripts.add(s.toLowerCase());
|
|
10758
|
+
}
|
|
10759
|
+
}
|
|
10760
|
+
return acc;
|
|
10761
|
+
}
|
|
10762
|
+
function foldAllowScripts(keys, allowScripts, acc) {
|
|
10763
|
+
let matchedKey;
|
|
10764
|
+
for (const key of keys) {
|
|
10765
|
+
const value = allowScripts && allowScripts[key];
|
|
10766
|
+
if (value !== void 0) {
|
|
10767
|
+
if (!matchedKey) matchedKey = key;
|
|
10768
|
+
normalizeAllowEntry(value, acc);
|
|
10769
|
+
}
|
|
10770
|
+
}
|
|
10771
|
+
return matchedKey;
|
|
10772
|
+
}
|
|
10773
|
+
function isTopLevelDep(depInfo) {
|
|
10774
|
+
return Boolean(depInfo && depInfo.top);
|
|
10775
|
+
}
|
|
10776
|
+
function evaluateScriptPolicy(depInfo, allowScripts, options = {}) {
|
|
10777
|
+
const urlType = getUrlType(depInfo);
|
|
10778
|
+
const keys = makeAllowKeys(depInfo);
|
|
10779
|
+
const topLevel = isTopLevelDep(depInfo);
|
|
10780
|
+
if (!urlType || TRUSTED_URL_TYPES.has(urlType)) {
|
|
10781
|
+
return { trusted: true, urlType, allowAll: true, allowed: /* @__PURE__ */ new Set(), key: keys[0], topLevel };
|
|
10782
|
+
}
|
|
10783
|
+
const acc = { allowAll: false, scripts: /* @__PURE__ */ new Set() };
|
|
10784
|
+
const matchedKey = foldAllowScripts(keys, allowScripts, acc);
|
|
10785
|
+
const { allowTopLevel } = options;
|
|
10786
|
+
if (topLevel && allowTopLevel !== void 0 && allowTopLevel !== false) {
|
|
10787
|
+
normalizeAllowEntry(allowTopLevel, acc);
|
|
10788
|
+
}
|
|
10789
|
+
return {
|
|
10790
|
+
trusted: false,
|
|
10791
|
+
urlType,
|
|
10792
|
+
allowAll: acc.allowAll,
|
|
10793
|
+
allowed: acc.scripts,
|
|
10794
|
+
// key to suggest when warning - prefer a matched key, else the spec form
|
|
10795
|
+
key: matchedKey || keys[0],
|
|
10796
|
+
topLevel
|
|
10797
|
+
};
|
|
10798
|
+
}
|
|
10799
|
+
function isScriptAllowed(policy, scriptName) {
|
|
10800
|
+
if (policy.trusted || policy.allowAll) {
|
|
10801
|
+
return true;
|
|
10802
|
+
}
|
|
10803
|
+
return policy.allowed.has(String(scriptName).toLowerCase());
|
|
10804
|
+
}
|
|
10805
|
+
module.exports = {
|
|
10806
|
+
TRUSTED_URL_TYPES,
|
|
10807
|
+
getSourceUrlType,
|
|
10808
|
+
getUrlType,
|
|
10809
|
+
isTrustedScriptSource,
|
|
10810
|
+
isTopLevelDep,
|
|
10811
|
+
makeAllowKeys,
|
|
10812
|
+
evaluateScriptPolicy,
|
|
10813
|
+
isScriptAllowed
|
|
10814
|
+
};
|
|
10815
|
+
|
|
10816
|
+
|
|
9990
10817
|
/***/ }),
|
|
9991
10818
|
|
|
9992
10819
|
/***/ "./lib/util/log-format.ts":
|
|
@@ -10007,6 +10834,7 @@ module.exports = {
|
|
|
10007
10834
|
* - the part before package name blue
|
|
10008
10835
|
* - the package name part magenta
|
|
10009
10836
|
* - remaining as is
|
|
10837
|
+
*
|
|
10010
10838
|
* @param {*} name - package name
|
|
10011
10839
|
* @param {*} path - path to highlight
|
|
10012
10840
|
* @returns
|
|
@@ -10106,7 +10934,7 @@ function makeNpmEnv(data, opts, prefix, env) {
|
|
|
10106
10934
|
if (minimalConfigKeys.includes(normalizedKey) || minimalConfigKeys.includes(key)) {
|
|
10107
10935
|
const envKey = `npm_config_${normalizedKey}`;
|
|
10108
10936
|
const val = opts.config[key];
|
|
10109
|
-
if (val
|
|
10937
|
+
if (val !== null && val !== void 0 && typeof val !== "function") {
|
|
10110
10938
|
env[envKey] = String(val);
|
|
10111
10939
|
}
|
|
10112
10940
|
}
|
|
@@ -10173,6 +11001,61 @@ ItemQueue.Promise = __webpack_require__("./lib/util/aveazul.ts");
|
|
|
10173
11001
|
module.exports = ItemQueue;
|
|
10174
11002
|
|
|
10175
11003
|
|
|
11004
|
+
/***/ }),
|
|
11005
|
+
|
|
11006
|
+
/***/ "./lib/util/registry-dep-policy.ts":
|
|
11007
|
+
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
|
|
11008
|
+
|
|
11009
|
+
"use strict";
|
|
11010
|
+
|
|
11011
|
+
const Semver = __webpack_require__("./node_modules/.f/_/semver/7.8.0/semver/index.js");
|
|
11012
|
+
const { TRUSTED_URL_TYPES, getSourceUrlType } = __webpack_require__("./lib/util/lifecycle-script-policy.ts");
|
|
11013
|
+
function isNonRegistryUrlType(urlType) {
|
|
11014
|
+
return Boolean(urlType) && !TRUSTED_URL_TYPES.has(urlType);
|
|
11015
|
+
}
|
|
11016
|
+
function isValidRegistrySpec(spec) {
|
|
11017
|
+
if (spec === void 0 || spec === null) {
|
|
11018
|
+
return false;
|
|
11019
|
+
}
|
|
11020
|
+
const s = String(spec).trim();
|
|
11021
|
+
if (s === "" || s === "*" || s === "x") {
|
|
11022
|
+
return true;
|
|
11023
|
+
}
|
|
11024
|
+
if (Semver.validRange(s) !== null) {
|
|
11025
|
+
return true;
|
|
11026
|
+
}
|
|
11027
|
+
if (Semver.coerce(s)) {
|
|
11028
|
+
return true;
|
|
11029
|
+
}
|
|
11030
|
+
return /^[a-zA-Z][\w.-]*$/.test(s);
|
|
11031
|
+
}
|
|
11032
|
+
function violatesRegistryPolicy(dep) {
|
|
11033
|
+
const urlType = dep.urlType;
|
|
11034
|
+
if (urlType) {
|
|
11035
|
+
if (TRUSTED_URL_TYPES.has(urlType)) {
|
|
11036
|
+
return null;
|
|
11037
|
+
}
|
|
11038
|
+
return { kind: "url", urlType };
|
|
11039
|
+
}
|
|
11040
|
+
if (dep.localType) {
|
|
11041
|
+
const sourceUrlType = getSourceUrlType(dep);
|
|
11042
|
+
if (isNonRegistryUrlType(sourceUrlType)) {
|
|
11043
|
+
return { kind: "local", urlType: sourceUrlType };
|
|
11044
|
+
}
|
|
11045
|
+
return null;
|
|
11046
|
+
}
|
|
11047
|
+
if (!isValidRegistrySpec(dep.semver)) {
|
|
11048
|
+
return { kind: "semver", semver: dep.semver };
|
|
11049
|
+
}
|
|
11050
|
+
return null;
|
|
11051
|
+
}
|
|
11052
|
+
module.exports = {
|
|
11053
|
+
isNonRegistryUrlType,
|
|
11054
|
+
isValidRegistrySpec,
|
|
11055
|
+
violatesRegistryPolicy
|
|
11056
|
+
};
|
|
11057
|
+
|
|
11058
|
+
|
|
10176
11059
|
/***/ }),
|
|
10177
11060
|
|
|
10178
11061
|
/***/ "./lib/util/run-npm-script.ts":
|
|
@@ -10279,11 +11162,14 @@ function simpleCompare(a, b) {
|
|
|
10279
11162
|
}
|
|
10280
11163
|
if (partsA[1]) {
|
|
10281
11164
|
if (partsB[1]) {
|
|
11165
|
+
if (Semver.valid(a) && Semver.valid(b)) {
|
|
11166
|
+
return Semver.rcompare(a, b);
|
|
11167
|
+
}
|
|
10282
11168
|
return partsA[1] > partsB[1] ? -1 : 1;
|
|
10283
11169
|
}
|
|
10284
|
-
return -1;
|
|
10285
|
-
} else if (partsB[1]) {
|
|
10286
11170
|
return 1;
|
|
11171
|
+
} else if (partsB[1]) {
|
|
11172
|
+
return -1;
|
|
10287
11173
|
} else {
|
|
10288
11174
|
return 0;
|
|
10289
11175
|
}
|
|
@@ -10567,7 +11453,7 @@ async function _scanFileStats(dir, ignores, baseDir = "") {
|
|
|
10567
11453
|
}
|
|
10568
11454
|
function scanFileStats(dir, options = {}) {
|
|
10569
11455
|
const ignores = [
|
|
10570
|
-
`**/?(node_modules|.vscode|.DS_Store|coverage|.nyc_output|.fynpo|.git|.github|.gitignore)`,
|
|
11456
|
+
`**/?(node_modules|_fyn|.vscode|.DS_Store|coverage|.nyc_output|.fynpo|.git|.github|.gitignore)`,
|
|
10571
11457
|
"**/*.?(log|md)"
|
|
10572
11458
|
].concat(options.ignores || `**/?(docs|docusaurus|packages|tmp|.etmp|samples|dist)`).concat(options.moreIgnores).filter((x) => x);
|
|
10573
11459
|
return _scanFileStats(dir, ignores, "");
|