Get the version number of an installed Node package without loading it? - node.js

It is possible to get the version of the current package via
const { version } = require('./package.json')
but how can I get the version number of an arbitrary, installed package without loading it?

I found a solution with require.resolve:
const path = require('path')
// get version number without requiring the module
function packageVersion(moduleName) {
const dir = path.dirname(require.resolve(moduleName))
return require(path.join(dir, 'package.json')).version
}

Related

Can't use crypto in NPM dependency in Electron app

I'm building an Electron app (with Ionic) to digitally sign PDFs with p12 certificates using node-signpdf (https://www.npmjs.com/package/node-signpdf). I've had problems which I solved by using require ('electron').remote for example for fs.
I've also installed the same node version in my OS (MacOS Catalina) as the same one that electron is using (Node v12.4.0).
The problem is that one of the NPM dependencies uses crypto and it shows as undefined with the next error:
HomePage.html:39 ERROR TypeError: _crypto.randomBytes is not a function
at Object.ctx.seedFileSync (prng.js:340)
at _reseedSync (prng.js:210)
at Object.ctx.generateSync (prng.js:163)
at Object.ctx.generate (prng.js:80)
at Object.ctx.getBytes (random.js:92)
at _modPow (rsa.js:431)
at Object.push../node_modules/node-forge/lib/rsa.js.pki.rsa.encrypt (rsa.js:501)
at Object.key.sign (rsa.js:1245)
at addSignerInfos (pkcs7.js:534)
at Object.sign (pkcs7.js:377)
What I can see is that node-signpdf uses node-forge as a dependency, and node-forge loads crypto inside prng.js this way:
var _crypto = null;
if(forge.util.isNodejs && !forge.options.usePureJavaScript &&
!process.versions['node-webkit']) {
_crypto = require('crypto');
}
I've tried changing that part of the code to use crypto-js or browserfy-crypto (this last one doesn't even build and hasn't been updated in years), but I keep getting the error shown above.
EDIT 1:
This is how I'm implementing the signature in my service:
public signFile(pathToFile: string, pathToCert: string): void {
const fs = (<any>window).require('fs');
let certBuffer = fs.readFileSync(pathToCert);
let fileBuffer = fs.readFileSync(pathToFile);
fileBuffer = plainAddPlaceholder({
pdfBuffer: fileBuffer,
reason: 'I have reviewed it.',
signatureLength: 1612,
});
const signedPdf = signer.sign(fileBuffer, certBuffer, {passphrase: 'qwertyui'});
}
The code adds the placeholder to add the signature, the problem comes in signer.sign
EDIT 2:
When I run the app if I type in console: require ('crypto') I see the methods, so it looks like it's loaded in the global scope, the problem seems to be in the NPM dependency of node-forge.
EDIT 3:
I've changed require('crypto') to window.require('crypto') and started working. But I think I'll have to make postinstall script to modify it.
Is there a better way?
-
How can I make this crypto thing work? I ran out of ideas. Maybe you can spare some?
Thanks for your time!

Node.js debug.enable for all dependencies

require('debug').enable('*')
It works ok for my program, but it does not work for packages that use debug too.
For example package needle, how to enable debug for this package?
How to enable debug for all the packages which use debug?
I want to switch on/off debug in runtime, without application restarting
const path = require('path')
const fs = require('fs')
fs.readdirSync('node_modules').forEach(f => {
try {
const debugPackage = path.join('./node_modules', f, '/node_modules/debug')
fs.statSync(debugPackage).isDirectory()
require(`./${debugPackage}/node.js`).enable('*')
}
catch (unused) {}
})
As a workaround

Permission denied when running fs-plus module

I'm writing package for Atom editor.
Can anyone help with persmission denied error I get when using fs-plus makeTree method in my package when running it on Mac? No errors on Windows.
I use fs-plus, the same module that Atom uses in its tree-view package (and tree-view works on Mac).
UPD: Adding screenshot, and some code:
New Folder option shown on the picture is implemented using the same module - fs-plus, and it works on Mac. I use just the same module, and the same method (fs-plus.makeTree) to create directory, but my implementation fails with Permission denied error.
My code:
import util from 'util';
import { sep } from 'path';
import fs from 'fs-plus';
const makeTreeAsync = util.promisify(fs.makeTree);
createTutorial(data) {
const { initialPath } = this;
const { fileName } = data;
const filePath = `${initialPath}${sep}${fileName}${sep}${fileName}.md`;
return makeTreeAsync(fileName)
.then(() => writeFileAsync(filePath, this.getContent(data)))
.then(() => filePath);
},
code from tree-view package:
path = require 'path'
fs = require 'fs-plus'
onConfirm: (newPath) ->
newPath = newPath.replace(/\s+$/, '') # Remove trailing whitespace
endsWithDirectorySeparator = newPath[newPath.length - 1] is path.sep
unless path.isAbsolute(newPath)
// some path preprocessing
return unless newPath
try
if fs.existsSync(newPath)
#showError("'#{newPath}' already exists.")
else if #isCreatingFile
// some code, we are not interested in as we 're creating directory
else
fs.makeTreeSync(newPath)
#emitter.emit('did-create-directory', newPath)
#cancel()
catch error
#showError("#{error.message}.")
Important note: my package is installed manually (copied to ~/<username>/.atom/packages) and then run npm i
After some time of debugging, I have a solution. I tried to use native fs.mkdir with no luck, but after I added mode as the second argument - it worked.
const _0777 = parseInt('0777', 8);
const mode = _0777 & (~process.umask());
fs.mkdir(<folderPath>, mode, () => {});
Hope, this will help someone.

Error: Cannot find module 'togeojson'

I am attempting to use this module in node.js and am running into an "Error: Cannot find module 'togeojson'" error when I attempt to use the documented example code:
// using togeojson in nodejs
var tj = require('togeojson'),
fs = require('fs'),
// node doesn't have xml parsing or a dom. use xmldom
DOMParser = require('xmldom').DOMParser;
var kml = new DOMParser().parseFromString(fs.readFileSync('foo.kml', 'utf8'));
var converted = tj.kml(kml);
var convertedWithStyles = tj.kml(kml, { styles: true });
I ran npm init in the same directory that my app.js file (where the above code resides) is stored and I used the --save flag when installing the #mapbox/togeojson package to my application.
I am running node version 8.11.2 and npm v 6.1.0.
How do I go about debugging an issue like this in node/npm?
It is #mapbox/togeojson package, not togeojson, so it should be required like:
var tj = require('#mapbox/togeojson');

What version of Node does my library support?

I'm hoping for a library or a tool which will run through my code and tell me what version of Node is required in order to run it. Perhaps better would be it alerts me to areas of the code which could be changed to support older versions.
Is there anything like that in the wild?
I'm not sure if this exactly what you are looking for, but there is an existing package.json property called "engines" where package developers can specify what version(s) they require. Not too difficult to use glob and semver packages to look through all package.json files with an "engines" requirement and compile that into an object of:
{
[version1]: [{ packageName, currentlySupported }, { ... }],
[version2]: [...],
...
}
Here is a rudimentary example of a script which will create that object for you:
npm install glob semver
checkversions.js:
const glob = require('glob');
const path = require('path');
const semver = require('semver');
const currentVersion = process.version;
const versions = {};
glob('node_modules/*/package.json', (err, files) => {
files.forEach((file) => {
const pkg = require(path.resolve(__dirname, file));
// only check add package if it specifies "engines"
if (pkg.engines && pkg.engines.node) {
const reqdVersion = pkg.engines.node.replace(/\s+/g, '');
// assume you are using a supported version
let currentlySupported = true;
// check if current node version satisfies package requirements
if (!semver.satisfies(currentVersion, reqdVersion)) {
currentlySupported = false;
}
if (!Array.isArray(versions[reqdVersion])) {
versions[reqdVersion] = [];
}
versions[reqdVersion].push({
package: file.replace(/node_modules\/(.*)\/package.json/, '$1'),
currentlySupported,
});
}
});
console.log(versions);
});
Run it:
node checkversions.js

Resources