949 lines
28 KiB
JavaScript
949 lines
28 KiB
JavaScript
'use strict';
|
|
/* eslint-disable require-atomic-updates */
|
|
var __createBinding =
|
|
(this && this.__createBinding) ||
|
|
(Object.create ?
|
|
function (o, m, k, k2) {
|
|
if (k2 === undefined) k2 = k;
|
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
if (
|
|
!desc ||
|
|
('get' in desc ? !m.__esModule : desc.writable || desc.configurable)
|
|
) {
|
|
desc = {
|
|
enumerable: true,
|
|
get: function () {
|
|
return m[k];
|
|
},
|
|
};
|
|
}
|
|
Object.defineProperty(o, k2, desc);
|
|
}
|
|
: function (o, m, k, k2) {
|
|
if (k2 === undefined) k2 = k;
|
|
o[k2] = m[k];
|
|
});
|
|
var __setModuleDefault =
|
|
(this && this.__setModuleDefault) ||
|
|
(Object.create ?
|
|
function (o, v) {
|
|
Object.defineProperty(o, 'default', { enumerable: true, value: v });
|
|
}
|
|
: function (o, v) {
|
|
o['default'] = v;
|
|
});
|
|
var __importStar =
|
|
(this && this.__importStar) ||
|
|
function (mod) {
|
|
if (mod && mod.__esModule) return mod;
|
|
var result = {};
|
|
if (mod != null)
|
|
for (var k in mod)
|
|
if (k !== 'default' && Object.prototype.hasOwnProperty.call(mod, k))
|
|
__createBinding(result, mod, k);
|
|
__setModuleDefault(result, mod);
|
|
return result;
|
|
};
|
|
var __importDefault =
|
|
(this && this.__importDefault) ||
|
|
function (mod) {
|
|
return mod && mod.__esModule ? mod : { default: mod };
|
|
};
|
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
const assert_1 = __importDefault(require('assert'));
|
|
const fs_extra_1 = __importDefault(require('fs-extra'));
|
|
const is_core_module_1 = __importDefault(require('is-core-module'));
|
|
const globby_1 = __importDefault(require('globby'));
|
|
const path_1 = __importDefault(require('path'));
|
|
const chalk_1 = __importDefault(require('chalk'));
|
|
const common_1 = require('./common');
|
|
const follow_1 = require('./follow');
|
|
const log_1 = require('./log');
|
|
const detector = __importStar(require('./detector'));
|
|
// Note: as a developer, you can set the PKG_STRICT_VER variable.
|
|
// this will turn on some assertion in the walker code below
|
|
// to assert that each file content/state that we appending
|
|
// to the virtual file system applies to a real file,
|
|
// not a symlink.
|
|
// By default assertion are disabled as they can have a
|
|
// performance hit.
|
|
const strictVerify = Boolean(process.env.PKG_STRICT_VER);
|
|
const win32 = process.platform === 'win32';
|
|
function unlikelyJavascript(file) {
|
|
return ['.css', '.html', '.json', '.vue'].includes(
|
|
path_1.default.extname(file)
|
|
);
|
|
}
|
|
function isPublic(config) {
|
|
if (config.private) {
|
|
return false;
|
|
}
|
|
const { licenses } = config;
|
|
let { license } = config;
|
|
if (licenses) {
|
|
license = licenses;
|
|
}
|
|
if (license && !Array.isArray(license)) {
|
|
license = typeof license === 'string' ? license : license.type;
|
|
}
|
|
if (Array.isArray(license)) {
|
|
license = license.map((c) => String(c.type || c)).join(',');
|
|
}
|
|
if (!license) {
|
|
return false;
|
|
}
|
|
if (/^\(/.test(license)) {
|
|
license = license.slice(1);
|
|
}
|
|
if (/\)$/.test(license)) {
|
|
license = license.slice(0, -1);
|
|
}
|
|
license = license.toLowerCase();
|
|
const allLicenses = Array.prototype.concat(
|
|
license.split(' or '),
|
|
license.split(' and '),
|
|
license.split('/'),
|
|
license.split(',')
|
|
);
|
|
let result = false;
|
|
const foss = [
|
|
'isc',
|
|
'mit',
|
|
'apache-2.0',
|
|
'apache 2.0',
|
|
'public domain',
|
|
'bsd',
|
|
'bsd-2-clause',
|
|
'bsd-3-clause',
|
|
'wtfpl',
|
|
'cc-by-3.0',
|
|
'x11',
|
|
'artistic-2.0',
|
|
'gplv3',
|
|
'mpl',
|
|
'mplv2.0',
|
|
'unlicense',
|
|
'apache license 2.0',
|
|
'zlib',
|
|
'mpl-2.0',
|
|
'nasa-1.3',
|
|
'apache license, version 2.0',
|
|
'lgpl-2.1+',
|
|
'cc0-1.0',
|
|
];
|
|
for (const c of allLicenses) {
|
|
result = foss.indexOf(c) >= 0;
|
|
if (result) {
|
|
break;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
function upon(p, base) {
|
|
if (typeof p !== 'string') {
|
|
throw (0, log_1.wasReported)('Config items must be strings. See examples');
|
|
}
|
|
let negate = false;
|
|
if (p[0] === '!') {
|
|
p = p.slice(1);
|
|
negate = true;
|
|
}
|
|
p = path_1.default.join(base, p);
|
|
if (win32) {
|
|
p = p.replace(/\\/g, '/');
|
|
}
|
|
if (negate) {
|
|
p = `!${p}`;
|
|
}
|
|
return p;
|
|
}
|
|
function collect(ps) {
|
|
return globby_1.default.sync(ps, { dot: true });
|
|
}
|
|
function expandFiles(efs, base) {
|
|
if (!Array.isArray(efs)) {
|
|
efs = [efs];
|
|
}
|
|
efs = collect(efs.map((p) => upon(p, base)));
|
|
return efs;
|
|
}
|
|
async function stepRead(record) {
|
|
if (strictVerify) {
|
|
(0, assert_1.default)(
|
|
record.file === (0, common_1.toNormalizedRealPath)(record.file)
|
|
);
|
|
}
|
|
let body;
|
|
try {
|
|
body = await fs_extra_1.default.readFile(record.file);
|
|
} catch (error) {
|
|
const exception = error;
|
|
log_1.log.error(`Cannot read file, ${exception.code}`, record.file);
|
|
throw (0, log_1.wasReported)(exception.message);
|
|
}
|
|
record.body = body;
|
|
}
|
|
function stepStrip(record) {
|
|
let body = (record.body || '').toString('utf8');
|
|
if (/^\ufeff/.test(body)) {
|
|
body = body.replace(/^\ufeff/, '');
|
|
}
|
|
if (/^#!/.test(body)) {
|
|
body = body.replace(/^#![^\n]*\n/, '\n');
|
|
}
|
|
record.body = body;
|
|
}
|
|
function stepDetect(record, marker, derivatives) {
|
|
let { body = '' } = record;
|
|
if (body instanceof Buffer) {
|
|
body = body.toString();
|
|
}
|
|
try {
|
|
detector.detect(body, (node, trying) => {
|
|
const { toplevel } = marker;
|
|
let d = detector.visitorSuccessful(node);
|
|
if (d) {
|
|
if (d.mustExclude) {
|
|
return false;
|
|
}
|
|
d.mayExclude = d.mayExclude || trying;
|
|
derivatives.push(d);
|
|
return false;
|
|
}
|
|
d = detector.visitorNonLiteral(node);
|
|
if (d) {
|
|
if (typeof d === 'object' && d.mustExclude) {
|
|
return false;
|
|
}
|
|
const debug = !toplevel || d.mayExclude || trying;
|
|
const level = debug ? 'debug' : 'warn';
|
|
log_1.log[level](`Cannot resolve '${d.alias}'`, [
|
|
record.file,
|
|
'Dynamic require may fail at run time, because the requested file',
|
|
'is unknown at compilation time and not included into executable.',
|
|
"Use a string literal as an argument for 'require', or leave it",
|
|
"as is and specify the resolved file name in 'scripts' option.",
|
|
]);
|
|
return false;
|
|
}
|
|
d = detector.visitorMalformed(node);
|
|
if (d) {
|
|
// there is no 'mustExclude'
|
|
const debug = !toplevel || trying;
|
|
const level = debug ? 'debug' : 'warn'; // there is no 'mayExclude'
|
|
log_1.log[level](`Malformed requirement for '${d.alias}'`, [
|
|
record.file,
|
|
]);
|
|
return false;
|
|
}
|
|
d = detector.visitorUseSCWD(node);
|
|
if (d) {
|
|
// there is no 'mustExclude'
|
|
const level = 'debug'; // there is no 'mayExclude'
|
|
log_1.log[level](`Path.resolve(${d.alias}) is ambiguous`, [
|
|
record.file,
|
|
"It resolves relatively to 'process.cwd' by default, however",
|
|
"you may want to use 'path.dirname(require.main.filename)'",
|
|
]);
|
|
return false;
|
|
}
|
|
return true; // can i go inside?
|
|
});
|
|
} catch (error) {
|
|
log_1.log.error(error.message, record.file);
|
|
throw (0, log_1.wasReported)(error.message);
|
|
}
|
|
}
|
|
function findCommonJunctionPoint(file, realFile) {
|
|
// find common denominator => where the link changes
|
|
while (
|
|
(0, common_1.toNormalizedRealPath)(path_1.default.dirname(file)) ===
|
|
path_1.default.dirname(realFile)
|
|
) {
|
|
file = path_1.default.dirname(file);
|
|
realFile = path_1.default.dirname(realFile);
|
|
}
|
|
return { file, realFile };
|
|
}
|
|
class Walker {
|
|
constructor() {
|
|
this.tasks = [];
|
|
this.records = {};
|
|
this.dictionary = {};
|
|
this.patches = {};
|
|
this.params = {};
|
|
this.symLinks = {};
|
|
}
|
|
appendRecord({ file, store }) {
|
|
if (this.records[file]) {
|
|
return;
|
|
}
|
|
if (
|
|
store === common_1.STORE_BLOB ||
|
|
store === common_1.STORE_CONTENT ||
|
|
store === common_1.STORE_LINKS
|
|
) {
|
|
// make sure we have a real file
|
|
if (strictVerify) {
|
|
(0, assert_1.default)(
|
|
file === (0, common_1.toNormalizedRealPath)(file)
|
|
);
|
|
}
|
|
}
|
|
this.records[file] = { file };
|
|
}
|
|
append(task) {
|
|
if (strictVerify) {
|
|
(0, assert_1.default)(typeof task.file === 'string');
|
|
(0, assert_1.default)(
|
|
task.file === (0, common_1.normalizePath)(task.file)
|
|
);
|
|
}
|
|
this.appendRecord(task);
|
|
this.tasks.push(task);
|
|
const what = {
|
|
[common_1.STORE_BLOB]: 'Bytecode of',
|
|
[common_1.STORE_CONTENT]: 'Content of',
|
|
[common_1.STORE_LINKS]: 'Directory',
|
|
[common_1.STORE_STAT]: 'Stat info of',
|
|
}[task.store];
|
|
if (task.reason) {
|
|
log_1.log.debug(
|
|
`${what} ${task.file} is added to queue. It was required from ${task.reason}`
|
|
);
|
|
} else {
|
|
log_1.log.debug(`${what} ${task.file} is added to queue.`);
|
|
}
|
|
}
|
|
appendSymlink(file, realFile) {
|
|
const a = findCommonJunctionPoint(file, realFile);
|
|
file = a.file;
|
|
realFile = a.realFile;
|
|
if (!this.symLinks[file]) {
|
|
const dn = path_1.default.dirname(file);
|
|
this.appendFileInFolder({
|
|
file: dn,
|
|
store: common_1.STORE_LINKS,
|
|
data: path_1.default.basename(file),
|
|
});
|
|
log_1.log.debug(
|
|
`adding symlink ${file} => ${path_1.default.relative(file, realFile)}`
|
|
);
|
|
this.symLinks[file] = realFile;
|
|
this.appendStat({
|
|
file: realFile,
|
|
store: common_1.STORE_STAT,
|
|
});
|
|
this.appendStat({
|
|
file: dn,
|
|
store: common_1.STORE_STAT,
|
|
});
|
|
this.appendStat({
|
|
file,
|
|
store: common_1.STORE_STAT,
|
|
});
|
|
}
|
|
}
|
|
appendStat(task) {
|
|
(0, assert_1.default)(task.store === common_1.STORE_STAT);
|
|
this.append(task);
|
|
}
|
|
appendFileInFolder(task) {
|
|
if (strictVerify) {
|
|
(0, assert_1.default)(task.store === common_1.STORE_LINKS);
|
|
(0, assert_1.default)(typeof task.file === 'string');
|
|
}
|
|
const realFile = (0, common_1.toNormalizedRealPath)(task.file);
|
|
if (realFile === task.file) {
|
|
this.append(task);
|
|
return;
|
|
}
|
|
this.append(Object.assign(Object.assign({}, task), { file: realFile }));
|
|
this.appendStat({
|
|
file: task.file,
|
|
store: common_1.STORE_STAT,
|
|
});
|
|
this.appendStat({
|
|
file: path_1.default.dirname(task.file),
|
|
store: common_1.STORE_STAT,
|
|
});
|
|
}
|
|
appendBlobOrContent(task) {
|
|
if (strictVerify) {
|
|
(0, assert_1.default)(
|
|
task.file === (0, common_1.normalizePath)(task.file)
|
|
);
|
|
}
|
|
(0, assert_1.default)(
|
|
task.store === common_1.STORE_BLOB ||
|
|
task.store === common_1.STORE_CONTENT
|
|
);
|
|
(0, assert_1.default)(typeof task.file === 'string');
|
|
const realFile = (0, common_1.toNormalizedRealPath)(task.file);
|
|
if (realFile === task.file) {
|
|
this.append(task);
|
|
return;
|
|
}
|
|
this.append(Object.assign(Object.assign({}, task), { file: realFile }));
|
|
this.appendSymlink(task.file, realFile);
|
|
this.appendStat({
|
|
file: task.file,
|
|
store: common_1.STORE_STAT,
|
|
});
|
|
}
|
|
async appendFilesFromConfig(marker) {
|
|
const { config, configPath, base } = marker;
|
|
const pkgConfig =
|
|
config === null || config === void 0 ? void 0 : config.pkg;
|
|
if (pkgConfig) {
|
|
let { scripts } = pkgConfig;
|
|
if (scripts) {
|
|
scripts = expandFiles(scripts, base);
|
|
for (const script of scripts) {
|
|
const stat = await fs_extra_1.default.stat(script);
|
|
if (stat.isFile()) {
|
|
if (
|
|
!(0, common_1.isDotJS)(script) &&
|
|
!(0, common_1.isDotJSON)(script) &&
|
|
!(0, common_1.isDotNODE)(script)
|
|
) {
|
|
log_1.log.warn("Non-javascript file is specified in 'scripts'.", [
|
|
'Pkg will probably fail to parse. Specify *.js in glob.',
|
|
script,
|
|
]);
|
|
}
|
|
this.appendBlobOrContent({
|
|
file: (0, common_1.normalizePath)(script),
|
|
marker,
|
|
store: common_1.STORE_BLOB,
|
|
reason: configPath,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
let { assets } = pkgConfig;
|
|
if (assets) {
|
|
assets = expandFiles(assets, base);
|
|
for (const asset of assets) {
|
|
log_1.log.debug(' Adding asset : .... ', asset);
|
|
const stat = await fs_extra_1.default.stat(asset);
|
|
if (stat.isFile()) {
|
|
this.appendBlobOrContent({
|
|
file: (0, common_1.normalizePath)(asset),
|
|
marker,
|
|
store: common_1.STORE_CONTENT,
|
|
reason: configPath,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
} else if (config) {
|
|
let { files } = config;
|
|
if (files) {
|
|
files = expandFiles(files, base);
|
|
for (let file of files) {
|
|
file = (0, common_1.normalizePath)(file);
|
|
const stat = await fs_extra_1.default.stat(file);
|
|
if (stat.isFile()) {
|
|
// 1) remove sources of top-level(!) package 'files' i.e. ship as BLOB
|
|
// 2) non-source (non-js) files of top-level package are shipped as CONTENT
|
|
// 3) parsing some js 'files' of non-top-level packages fails, hence all CONTENT
|
|
if (marker.toplevel) {
|
|
this.appendBlobOrContent({
|
|
file,
|
|
marker,
|
|
store:
|
|
(0, common_1.isDotJS)(file) ?
|
|
common_1.STORE_BLOB
|
|
: common_1.STORE_CONTENT,
|
|
reason: configPath,
|
|
});
|
|
} else {
|
|
this.appendBlobOrContent({
|
|
file,
|
|
marker,
|
|
store: common_1.STORE_CONTENT,
|
|
reason: configPath,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
async stepActivate(marker, derivatives) {
|
|
if (!marker) {
|
|
(0, assert_1.default)(false);
|
|
}
|
|
if (marker.activated) {
|
|
return;
|
|
}
|
|
const { config, base } = marker;
|
|
if (!config) {
|
|
(0, assert_1.default)(false);
|
|
}
|
|
const { name } = config;
|
|
if (name) {
|
|
const d = this.dictionary[name];
|
|
if (d) {
|
|
if (
|
|
typeof config.dependencies === 'object' &&
|
|
typeof d.dependencies === 'object'
|
|
) {
|
|
Object.assign(config.dependencies, d.dependencies);
|
|
delete d.dependencies;
|
|
}
|
|
Object.assign(config, d);
|
|
marker.hasDictionary = true;
|
|
}
|
|
}
|
|
const { dependencies } = config;
|
|
if (typeof dependencies === 'object') {
|
|
for (const dependency in dependencies) {
|
|
// it may be `undefined` - overridden
|
|
// in dictionary (see publicsuffixlist)
|
|
if (dependencies[dependency]) {
|
|
derivatives.push({
|
|
alias: dependency,
|
|
aliasType: common_1.ALIAS_AS_RESOLVABLE,
|
|
fromDependencies: true,
|
|
});
|
|
derivatives.push({
|
|
alias: `${dependency}/package.json`,
|
|
aliasType: common_1.ALIAS_AS_RESOLVABLE,
|
|
fromDependencies: true,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
const pkgConfig = config.pkg;
|
|
if (pkgConfig) {
|
|
const { patches } = pkgConfig;
|
|
if (patches) {
|
|
for (const key in patches) {
|
|
if (patches[key]) {
|
|
const p = path_1.default.join(base, key);
|
|
this.patches[p] = patches[key];
|
|
}
|
|
}
|
|
}
|
|
const { deployFiles } = pkgConfig;
|
|
if (deployFiles) {
|
|
marker.hasDeployFiles = true;
|
|
for (const deployFile of deployFiles) {
|
|
const type = deployFile[2] || 'file';
|
|
log_1.log.warn(`Cannot include ${type} %1 into executable.`, [
|
|
`The ${type} must be distributed with executable as %2.`,
|
|
`%1: ${path_1.default.relative(process.cwd(), path_1.default.join(base, deployFile[0]))}`,
|
|
`%2: path-to-executable/${deployFile[1]}`,
|
|
]);
|
|
}
|
|
}
|
|
if (pkgConfig.log) {
|
|
pkgConfig.log(log_1.log, { packagePath: base });
|
|
}
|
|
}
|
|
await this.appendFilesFromConfig(marker);
|
|
marker.public = isPublic(config);
|
|
if (!marker.public && marker.toplevel) {
|
|
marker.public = this.params.publicToplevel;
|
|
}
|
|
if (!marker.public && !marker.toplevel && this.params.publicPackages) {
|
|
marker.public =
|
|
this.params.publicPackages[0] === '*' ||
|
|
(!!name && this.params.publicPackages.indexOf(name) !== -1);
|
|
}
|
|
marker.activated = true;
|
|
// assert no further work with config
|
|
delete marker.config;
|
|
}
|
|
hasPatch(record) {
|
|
const patch = this.patches[record.file];
|
|
if (!patch) {
|
|
return;
|
|
}
|
|
return true;
|
|
}
|
|
stepPatch(record) {
|
|
const patch = this.patches[record.file];
|
|
if (!patch) {
|
|
return;
|
|
}
|
|
let body = (record.body || '').toString('utf8');
|
|
for (let i = 0; i < patch.length; i += 2) {
|
|
if (typeof patch[i] === 'object') {
|
|
if (patch[i].do === 'erase') {
|
|
body = patch[i + 1];
|
|
} else if (patch[i].do === 'prepend') {
|
|
body = patch[i + 1] + body;
|
|
} else if (patch[i].do === 'append') {
|
|
body += patch[i + 1];
|
|
}
|
|
} else if (typeof patch[i] === 'string') {
|
|
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions
|
|
// function escapeRegExp
|
|
const esc = patch[i].replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
const regexp = new RegExp(esc, 'g');
|
|
body = body.replace(regexp, patch[i + 1]);
|
|
}
|
|
}
|
|
record.body = body;
|
|
}
|
|
async stepDerivatives_ALIAS_AS_RELATIVE(record, marker, derivative) {
|
|
const file = (0, common_1.normalizePath)(
|
|
path_1.default.join(path_1.default.dirname(record.file), derivative.alias)
|
|
);
|
|
let stat;
|
|
try {
|
|
stat = await fs_extra_1.default.stat(file);
|
|
} catch (error) {
|
|
const { toplevel } = marker;
|
|
const exception = error;
|
|
const debug = !toplevel && exception.code === 'ENOENT';
|
|
const level = debug ? 'debug' : 'warn';
|
|
log_1.log[level](`Cannot stat, ${exception.code}`, [
|
|
file,
|
|
`The file was required from '${record.file}'`,
|
|
]);
|
|
}
|
|
if (stat && stat.isFile()) {
|
|
this.appendBlobOrContent({
|
|
file,
|
|
marker,
|
|
store: common_1.STORE_CONTENT,
|
|
reason: record.file,
|
|
});
|
|
}
|
|
}
|
|
async stepDerivatives_ALIAS_AS_RESOLVABLE(record, marker, derivative) {
|
|
var _a, _b;
|
|
const newPackages = [];
|
|
const catchReadFile = (file) => {
|
|
(0, assert_1.default)(
|
|
(0, common_1.isPackageJson)(file),
|
|
`walker: ${file} must be package.json`
|
|
);
|
|
newPackages.push({ packageJson: file });
|
|
};
|
|
const catchPackageFilter = (config, base) => {
|
|
const newPackage = newPackages[newPackages.length - 1];
|
|
newPackage.marker = { config, configPath: newPackage.packageJson, base };
|
|
};
|
|
let newFile = '';
|
|
let failure;
|
|
const basedir = path_1.default.dirname(record.file);
|
|
try {
|
|
newFile = await (0, follow_1.follow)(derivative.alias, {
|
|
basedir,
|
|
// default is extensions: ['.js'], but
|
|
// it is not enough because 'typos.json'
|
|
// is not taken in require('./typos')
|
|
// in 'normalize-package-data/lib/fixer.js'
|
|
extensions: ['.js', '.json', '.node'],
|
|
catchReadFile,
|
|
catchPackageFilter,
|
|
});
|
|
} catch (error) {
|
|
failure = error;
|
|
}
|
|
if (failure) {
|
|
const { toplevel } = marker;
|
|
const mainNotFound =
|
|
newPackages.length > 0 &&
|
|
!((
|
|
(_b =
|
|
(_a = newPackages[0].marker) === null || _a === void 0 ?
|
|
void 0
|
|
: _a.config) === null || _b === void 0
|
|
) ?
|
|
void 0
|
|
: _b.main);
|
|
const debug =
|
|
!toplevel ||
|
|
derivative.mayExclude ||
|
|
(mainNotFound && derivative.fromDependencies);
|
|
const level = debug ? 'debug' : 'warn';
|
|
if (mainNotFound) {
|
|
const message = "Entry 'main' not found in %1";
|
|
log_1.log[level](message, [
|
|
`%1: ${newPackages[0].packageJson}`,
|
|
`%2: ${record.file}`,
|
|
]);
|
|
} else {
|
|
log_1.log[level](
|
|
`${chalk_1.default.yellow(failure.message)} in ${record.file}`
|
|
);
|
|
}
|
|
return;
|
|
}
|
|
let newPackageForNewRecords;
|
|
for (const newPackage of newPackages) {
|
|
let newFile2;
|
|
try {
|
|
newFile2 = await (0, follow_1.follow)(derivative.alias, {
|
|
basedir: path_1.default.dirname(record.file),
|
|
extensions: ['.js', '.json', '.node'],
|
|
ignoreFile: newPackage.packageJson,
|
|
});
|
|
if (strictVerify) {
|
|
(0, assert_1.default)(
|
|
newFile2 === (0, common_1.normalizePath)(newFile2)
|
|
);
|
|
}
|
|
} catch (_) {
|
|
// not setting is enough
|
|
}
|
|
if (newFile2 !== newFile) {
|
|
newPackageForNewRecords = newPackage;
|
|
break;
|
|
}
|
|
}
|
|
if (newPackageForNewRecords) {
|
|
if (strictVerify) {
|
|
(0, assert_1.default)(
|
|
newPackageForNewRecords.packageJson ===
|
|
(0, common_1.normalizePath)(newPackageForNewRecords.packageJson)
|
|
);
|
|
}
|
|
this.appendBlobOrContent({
|
|
file: newPackageForNewRecords.packageJson,
|
|
marker: newPackageForNewRecords.marker,
|
|
store: common_1.STORE_CONTENT,
|
|
reason: record.file,
|
|
});
|
|
}
|
|
this.appendBlobOrContent({
|
|
file: newFile,
|
|
marker: newPackageForNewRecords ? newPackageForNewRecords.marker : marker,
|
|
store: common_1.STORE_BLOB,
|
|
reason: record.file,
|
|
});
|
|
}
|
|
async stepDerivatives(record, marker, derivatives) {
|
|
for (const derivative of derivatives) {
|
|
// TODO: actually use the target node version
|
|
if ((0, is_core_module_1.default)(derivative.alias, '99.0.0')) continue;
|
|
switch (derivative.aliasType) {
|
|
case common_1.ALIAS_AS_RELATIVE:
|
|
await this.stepDerivatives_ALIAS_AS_RELATIVE(
|
|
record,
|
|
marker,
|
|
derivative
|
|
);
|
|
break;
|
|
case common_1.ALIAS_AS_RESOLVABLE:
|
|
await this.stepDerivatives_ALIAS_AS_RESOLVABLE(
|
|
record,
|
|
marker,
|
|
derivative
|
|
);
|
|
break;
|
|
default:
|
|
(0, assert_1.default)(
|
|
false,
|
|
`walker: unknown aliasType ${derivative.aliasType}`
|
|
);
|
|
}
|
|
}
|
|
}
|
|
async step_STORE_ANY(record, marker, store) {
|
|
if (strictVerify) {
|
|
(0, assert_1.default)(
|
|
record.file === (0, common_1.toNormalizedRealPath)(record.file)
|
|
);
|
|
}
|
|
if (record[store] !== undefined) return;
|
|
record[store] = false; // default is discard
|
|
this.appendStat({
|
|
file: record.file,
|
|
store: common_1.STORE_STAT,
|
|
});
|
|
const derivatives1 = [];
|
|
await this.stepActivate(marker, derivatives1);
|
|
await this.stepDerivatives(record, marker, derivatives1);
|
|
if (store === common_1.STORE_BLOB) {
|
|
if (
|
|
unlikelyJavascript(record.file) ||
|
|
(0, common_1.isDotNODE)(record.file)
|
|
) {
|
|
this.appendBlobOrContent({
|
|
file: record.file,
|
|
marker,
|
|
store: common_1.STORE_CONTENT,
|
|
});
|
|
return; // discard
|
|
}
|
|
if (marker.public || marker.hasDictionary) {
|
|
this.appendBlobOrContent({
|
|
file: record.file,
|
|
marker,
|
|
store: common_1.STORE_CONTENT,
|
|
});
|
|
}
|
|
}
|
|
if (store === common_1.STORE_BLOB || this.hasPatch(record)) {
|
|
if (!record.body) {
|
|
await stepRead(record);
|
|
this.stepPatch(record);
|
|
if (store === common_1.STORE_BLOB) {
|
|
stepStrip(record);
|
|
}
|
|
}
|
|
if (store === common_1.STORE_BLOB) {
|
|
const derivatives2 = [];
|
|
stepDetect(record, marker, derivatives2);
|
|
await this.stepDerivatives(record, marker, derivatives2);
|
|
}
|
|
}
|
|
record[store] = true;
|
|
}
|
|
step_STORE_LINKS(record, data) {
|
|
if (strictVerify) {
|
|
(0, assert_1.default)(
|
|
record.file === (0, common_1.toNormalizedRealPath)(record.file),
|
|
' expecting real file !!!'
|
|
);
|
|
}
|
|
if (record[common_1.STORE_LINKS]) {
|
|
record[common_1.STORE_LINKS].push(data);
|
|
return;
|
|
}
|
|
record[common_1.STORE_LINKS] = [data];
|
|
if (record[common_1.STORE_STAT]) {
|
|
return;
|
|
}
|
|
this.appendStat({
|
|
file: record.file,
|
|
store: common_1.STORE_STAT,
|
|
});
|
|
}
|
|
async step_STORE_STAT(record) {
|
|
if (record[common_1.STORE_STAT]) return;
|
|
const realPath = (0, common_1.toNormalizedRealPath)(record.file);
|
|
if (realPath !== record.file) {
|
|
this.appendStat({
|
|
file: realPath,
|
|
store: common_1.STORE_STAT,
|
|
});
|
|
}
|
|
try {
|
|
const valueStat = await fs_extra_1.default.stat(record.file);
|
|
const value = {
|
|
mode: valueStat.mode,
|
|
size: valueStat.isFile() ? valueStat.size : 0,
|
|
isFileValue: valueStat.isFile(),
|
|
isDirectoryValue: valueStat.isDirectory(),
|
|
isSocketValue: valueStat.isSocket(),
|
|
isSymbolicLinkValue: valueStat.isSymbolicLink(),
|
|
};
|
|
record[common_1.STORE_STAT] = value;
|
|
} catch (error) {
|
|
const exception = error;
|
|
log_1.log.error(`Cannot stat, ${exception.code}`, record.file);
|
|
throw (0, log_1.wasReported)(exception.message);
|
|
}
|
|
if (path_1.default.dirname(record.file) !== record.file) {
|
|
// root directory
|
|
this.appendFileInFolder({
|
|
file: path_1.default.dirname(record.file),
|
|
store: common_1.STORE_LINKS,
|
|
data: path_1.default.basename(record.file),
|
|
});
|
|
}
|
|
}
|
|
async step(task) {
|
|
const { file, store, data } = task;
|
|
const record = this.records[file];
|
|
switch (store) {
|
|
case common_1.STORE_BLOB:
|
|
case common_1.STORE_CONTENT:
|
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
await this.step_STORE_ANY(record, task.marker, store);
|
|
break;
|
|
case common_1.STORE_LINKS:
|
|
this.step_STORE_LINKS(record, data);
|
|
break;
|
|
case common_1.STORE_STAT:
|
|
await this.step_STORE_STAT(record);
|
|
break;
|
|
default:
|
|
(0, assert_1.default)(false, `walker: unknown store ${store}`);
|
|
}
|
|
}
|
|
async readDictionary(marker) {
|
|
var _a, _b, _c;
|
|
if (
|
|
((_a = this.params.noDictionary) === null || _a === void 0 ?
|
|
void 0
|
|
: _a[0]) === '*'
|
|
) {
|
|
return;
|
|
}
|
|
const dd = path_1.default.join(__dirname, '../dictionary');
|
|
const files = await fs_extra_1.default.readdir(dd);
|
|
for (const file of files) {
|
|
if (/\.js$/.test(file)) {
|
|
const name = file.slice(0, -3);
|
|
if (
|
|
(_b = this.params.noDictionary) === null || _b === void 0 ?
|
|
void 0
|
|
: _b.includes(file)
|
|
) {
|
|
continue;
|
|
}
|
|
// eslint-disable-next-line import/no-dynamic-require, global-require, @typescript-eslint/no-var-requires
|
|
const config = require(path_1.default.join(dd, file));
|
|
this.dictionary[name] = config;
|
|
}
|
|
}
|
|
const pkgConfig =
|
|
(_c = marker.config) === null || _c === void 0 ? void 0 : _c.pkg;
|
|
if (pkgConfig) {
|
|
const { dictionary } = pkgConfig;
|
|
if (dictionary) {
|
|
for (const name in dictionary) {
|
|
if (dictionary[name]) {
|
|
this.dictionary[name] = { pkg: dictionary[name] };
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
async start(marker, entrypoint, addition, params) {
|
|
this.params = params;
|
|
this.symLinks = {};
|
|
await this.readDictionary(marker);
|
|
entrypoint = (0, common_1.normalizePath)(entrypoint);
|
|
this.appendBlobOrContent({
|
|
file: entrypoint,
|
|
marker,
|
|
store: common_1.STORE_BLOB,
|
|
});
|
|
if (addition) {
|
|
addition = (0, common_1.normalizePath)(addition);
|
|
this.appendBlobOrContent({
|
|
file: addition,
|
|
marker,
|
|
store: common_1.STORE_CONTENT,
|
|
});
|
|
}
|
|
const { tasks } = this;
|
|
for (let i = 0; i < tasks.length; i += 1) {
|
|
// NO MULTIPLE WORKERS! THIS WILL LEAD TO NON-DETERMINISTIC
|
|
// ORDER. one-by-one fifo is the only way to iterate tasks
|
|
await this.step(tasks[i]);
|
|
}
|
|
return {
|
|
symLinks: this.symLinks,
|
|
records: this.records,
|
|
entrypoint: (0, common_1.normalizePath)(entrypoint),
|
|
};
|
|
}
|
|
}
|
|
async function walker(...args) {
|
|
const w = new Walker();
|
|
return w.start(...args);
|
|
}
|
|
exports.default = walker;
|
|
//# sourceMappingURL=walker.js.map
|