Skip to content

Commit

Permalink
[Breaking] bump to npm 10 and node 18; getDeprecationMessages now out…
Browse files Browse the repository at this point in the history
…puts a single object instead of an array of them
  • Loading branch information
ljharb committed Jan 19, 2024
1 parent cac9d48 commit 46c72d7
Show file tree
Hide file tree
Showing 11 changed files with 156 additions and 198 deletions.
16 changes: 3 additions & 13 deletions .eslintrc
Original file line number Diff line number Diff line change
@@ -1,21 +1,11 @@
{
"root": true,

"extends": "@ljharb",
"extends": "@ljharb/eslint-config/node/18",

"rules": {
"id-length": [2, { "min": 1, "max": 30 }],
"max-nested-callbacks": [2, 3],
"max-statements-per-line": [2, { "max": 2 }],
"no-unused-vars": [1]
"no-unused-vars": 1,
"prefer-rest-params": 0,
},

"overrides": [
{
"files": "test/**",
"rules": {
"max-lines-per-function": 0,
},
},
],
}
2 changes: 1 addition & 1 deletion .github/workflows/node.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ jobs:
tests:
uses: ljharb/actions/.github/workflows/node.yml@main
with:
range: '^6.2 || ^7 || ^8 || ^9.3 || ^10 || >= 11.2'
range: '^18.17.0 || >=20.5.0'
type: minors
command: npm run tests-only

Expand Down
10 changes: 6 additions & 4 deletions bin.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@

'use strict';

var deprecations = require('./');
const deprecations = require('./');

var modules = process.argv.slice(2);
const modules = process.argv.slice(2);

/* eslint-disable no-console */
if (modules.length > 0) {
deprecations.apply(null, modules).then(function (messages) {
deprecations(...modules).then((messages) => {
console.log(JSON.stringify(messages, null, '\t'));
}, (err) => {
process.exitCode = 1;
console.error(err);
});
} else {
console.log('usage: deprecations module1 [module2...]\n\tOutputs JSON.');
Expand Down
48 changes: 14 additions & 34 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,48 +1,28 @@
'use strict';

var toStr = Object.prototype.toString;
var slice = Array.prototype.slice;
var isString = function (str) { return toStr.call(str) === '[object String]'; };
var isFunction = function (func) { return toStr.call(func) === '[object Function]'; };
const every = require('array.prototype.every');
const fromEntries = require('object.fromentries');

var promiseback = require('promiseback');
var Promise = require('./promise');
var assign = require('object.assign');
const isString = (str) => typeof str === 'string';

var getVersions = require('./versions');
var getDeprecationMessages = require('./messages');
const getVersions = require('./versions');
const getDeprecationMessages = require('./messages');

module.exports = function deprecations(packageName) {
var callback;
module.exports = function deprecations(packageName, ...morePackageNames) {
if (arguments.length < 1) {
throw new TypeError('at least 1 package name is required');
} else if (arguments.length > 1 && isFunction(arguments[arguments.length - 1])) {
callback = arguments[arguments.length - 1];
}

var modules = slice.call(arguments, 0, callback ? -1 : callback);
if (!modules.every(isString)) {
if (!every(arguments, isString)) {
throw new TypeError('module names must all be strings');
}

var deferred = promiseback(callback);
process.nextTick(function () {
var promises = modules.map(function (name) {
return getVersions(name).then(function (versions) {
return getDeprecationMessages(name, versions);
}).then(function (data) {
var moduleData = {};
moduleData[name] = assign.apply(null, [{}].concat(data));
return moduleData;
});
});
Promise.all(promises).then(function (moduleDatas) {
var modulesData = moduleDatas.reduce(function (acc, moduleData) {
return assign(acc, moduleData);
}, {});
deferred.resolve(modulesData);
}, deferred.reject);
});
return deferred.promise;
return Promise.all(Array.from(arguments, async (name) => {
const versions = await getVersions(name);
return [
name,
await getDeprecationMessages(name, versions),
];
})).then(fromEntries);
};

44 changes: 20 additions & 24 deletions messages.js
Original file line number Diff line number Diff line change
@@ -1,31 +1,27 @@
'use strict';

var Promise = require('./promise');
var exec = require('child_process').exec;
const { exec } = require('child_process');
const fromEntries = require('object.fromentries');

module.exports = function getDeprecationMessages(name, versions) {
var promises = versions.map(function (version) {
return new Promise(function (resolve, reject) {
exec('npm info ' + name + '@' + version + ' deprecated --json --no-spin --silent', function (err, jsonMsg) {
if (err) { return reject(err); }
var message = String(jsonMsg).trim();
module.exports = async function getDeprecationMessages(name, versions) {
return fromEntries(await Promise.all(versions.map(async (version) => {
const jsonMsg = await new Promise((resolve, reject) => {
exec(`npm info ${name}@${version} deprecated --json --no-spin --silent`, (err, data) => {
if (err) {
return reject(err);
}
const message = String(data).trim();
return message ? resolve(message) : resolve();
});
}).then(function (jsonMsg) {
if (typeof jsonMsg !== 'undefined' && jsonMsg !== 'undefined') {
return JSON.parse(jsonMsg);
}
return null;
}).then(function (fullMsg) {
var msg = fullMsg ? String(fullMsg).trim() : '';
var finalMessage;
if (msg && msg.length > 0) {
finalMessage = msg;
}
var finalData = {};
finalData[version] = finalMessage;
return finalData;
});
});
return Promise.all(promises);
const fullMsg = typeof jsonMsg !== 'undefined' && jsonMsg !== 'undefined' ? JSON.parse(jsonMsg) : null;

const msg = fullMsg ? String(fullMsg).trim() : '';

let finalMessage;
if (msg && msg.length > 0) {
finalMessage = msg;
}
return [version, finalMessage];
})));
};
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@
"deprecation messages"
],
"dependencies": {
"object.assign": "^4.1.4",
"promiseback": "^2.0.3"
"array.prototype.every": "^1.1.5",
"object.fromentries": "^2.0.7"
},
"devDependencies": {
"@ljharb/eslint-config": "^21.0.0",
Expand All @@ -52,8 +52,8 @@
"tape": "^5.6.1"
},
"engines": {
"npm": "^6.13.4 || ^7 || ^8",
"node": "^6.2 || ^7 || ^8 || ^9.3 || ^10 || >= 11.2"
"npm": ">= 10",
"node": "^18.17.0 || >=20.5.0"
},
"publishConfig": {
"ignore": [
Expand Down
3 changes: 0 additions & 3 deletions promise.js

This file was deleted.

124 changes: 61 additions & 63 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,82 +3,80 @@
require('./messages');
require('./versions');

var deprecations = require('../');
var test = require('tape');
const deprecations = require('../');
const test = require('tape');

var compact = function (obj) {
return Object.keys(obj).reduce(function (map, key) {
const compact = function (obj) {
return Object.keys(obj).reduce((map, key) => {
if (obj[key]) {
map[key] = obj[key]; // eslint-disable-line no-param-reassign
}
return map;
}, {});
};

test('errors', function (t) {
t['throws'](deprecations, new TypeError('at least 1 package name is required'));
t['throws'](function () { deprecations(3); }, new TypeError('module names must all be strings'));
t['throws'](function () { deprecations('foo', 3); }, new TypeError('module names must all be strings'));
t['throws'](function () { deprecations(3, 'foo'); }, new TypeError('module names must all be strings'));
test('errors', (t) => {
t.throws(deprecations, new TypeError('at least 1 package name is required'));
t.throws(() => { deprecations(3); }, new TypeError('module names must all be strings'));
t.throws(() => { deprecations('foo', 3); }, new TypeError('module names must all be strings'));
t.throws(() => { deprecations(3, 'foo'); }, new TypeError('module names must all be strings'));
t.end();
});

test('works', function (t) {
var formMessages = {
'0.1.0': 'Please update to the latest version to ensure the latest security fixes in "qs"',
'0.1.1': 'Please update to the latest version to ensure the latest security fixes in "qs"',
'0.1.2': 'Please update to the latest version to ensure the latest security fixes in "qs"',
'0.1.3': 'Please update to the latest version to ensure the latest security fixes in "qs"',
'0.1.4': 'Please update to the latest version to ensure the latest security fixes in "qs"',
'0.2.0': 'Please update to the latest version to ensure the latest security fixes in "qs"',
'0.2.1': 'Please update to the latest version to ensure the latest security fixes in "qs"',
'0.2.2': 'Please update to the latest version to ensure the latest security fixes in "qs"',
'0.2.3': 'Please update to the latest version to ensure the latest security fixes in "qs"',
'0.3.0': 'Please update to the latest version to ensure the latest security fixes in "qs"',
'0.4.0': 'Please update to the latest version to ensure the latest security fixes in "qs"',
'0.4.1': 'Please update to the latest version to ensure the latest security fixes in "qs"',
'0.5.0': 'Please update to the latest version to ensure the latest security fixes in "qs"',
'0.6.0': 'Please update to the latest version to ensure the latest security fixes in "qs"',
'0.7.0': 'Please update to the latest version to ensure the latest security fixes in "qs"',
'0.8.1': 'Please update to the latest version to ensure the latest security fixes in "qs"',
'0.9.0': 'Please update to the latest version to ensure the latest security fixes in "qs"',
'0.9.1': 'Please update to ^1.3.0 to ensure your HTML content is properly escaped.',
'0.9.2': 'Please update to ^1.3.0 to ensure your HTML content is properly escaped.',
'0.9.3': 'Please update to ^1.3.0 to ensure your HTML content is properly escaped.',
'0.9.4': 'Please update to ^1.3.0 to ensure your HTML content is properly escaped.',
'0.9.5': 'Please update to ^1.3.0 to ensure your HTML content is properly escaped.',
'0.9.6': 'Please update to ^1.3.0 to ensure your HTML content is properly escaped.',
'0.10.0': 'Please update to ^1.3.0 to ensure your HTML content is properly escaped.',
'1.0.0': 'Please update to ^1.3.0 to ensure your HTML content is properly escaped.',
'1.1.0': 'Please update to ^1.3.0 to ensure your HTML content is properly escaped.',
'1.1.1': 'Please update to ^1.3.0 to ensure your HTML content is properly escaped.',
'1.1.3': 'Please update to ^1.3.0 to ensure your HTML content is properly escaped.',
'1.1.4': 'Please update to ^1.3.0 to ensure your HTML content is properly escaped.',
'1.2.0': 'Please update to ^1.3.0 to ensure your HTML content is properly escaped.'
};
const formMessages = {
'0.1.0': 'Please update to the latest version to ensure the latest security fixes in "qs"',
'0.1.1': 'Please update to the latest version to ensure the latest security fixes in "qs"',
'0.1.2': 'Please update to the latest version to ensure the latest security fixes in "qs"',
'0.1.3': 'Please update to the latest version to ensure the latest security fixes in "qs"',
'0.1.4': 'Please update to the latest version to ensure the latest security fixes in "qs"',
'0.2.0': 'Please update to the latest version to ensure the latest security fixes in "qs"',
'0.2.1': 'Please update to the latest version to ensure the latest security fixes in "qs"',
'0.2.2': 'Please update to the latest version to ensure the latest security fixes in "qs"',
'0.2.3': 'Please update to the latest version to ensure the latest security fixes in "qs"',
'0.3.0': 'Please update to the latest version to ensure the latest security fixes in "qs"',
'0.4.0': 'Please update to the latest version to ensure the latest security fixes in "qs"',
'0.4.1': 'Please update to the latest version to ensure the latest security fixes in "qs"',
'0.5.0': 'Please update to the latest version to ensure the latest security fixes in "qs"',
'0.6.0': 'Please update to the latest version to ensure the latest security fixes in "qs"',
'0.7.0': 'Please update to the latest version to ensure the latest security fixes in "qs"',
'0.8.1': 'Please update to the latest version to ensure the latest security fixes in "qs"',
'0.9.0': 'Please update to the latest version to ensure the latest security fixes in "qs"',
'0.9.1': 'Please update to ^1.3.0 to ensure your HTML content is properly escaped.',
'0.9.2': 'Please update to ^1.3.0 to ensure your HTML content is properly escaped.',
'0.9.3': 'Please update to ^1.3.0 to ensure your HTML content is properly escaped.',
'0.9.4': 'Please update to ^1.3.0 to ensure your HTML content is properly escaped.',
'0.9.5': 'Please update to ^1.3.0 to ensure your HTML content is properly escaped.',
'0.9.6': 'Please update to ^1.3.0 to ensure your HTML content is properly escaped.',
'0.10.0': 'Please update to ^1.3.0 to ensure your HTML content is properly escaped.',
'1.0.0': 'Please update to ^1.3.0 to ensure your HTML content is properly escaped.',
'1.1.0': 'Please update to ^1.3.0 to ensure your HTML content is properly escaped.',
'1.1.1': 'Please update to ^1.3.0 to ensure your HTML content is properly escaped.',
'1.1.3': 'Please update to ^1.3.0 to ensure your HTML content is properly escaped.',
'1.1.4': 'Please update to ^1.3.0 to ensure your HTML content is properly escaped.',
'1.2.0': 'Please update to ^1.3.0 to ensure your HTML content is properly escaped.',
};

test('works', (t) => {
t.test('with one module', async (st) => {
const messages = await deprecations('forms');

t.test('with one module', function (st) {
st.plan(2);
deprecations('forms').then(function (messages) {
st.deepEqual(Object.keys(messages), ['forms'], 'has just one key');
st.deepEqual(compact(messages.forms), formMessages, 'forms messages match');
}).then(null, st.fail);
st.deepEqual(Object.keys(messages), ['forms'], 'has just one key');
st.deepEqual(compact(messages.forms), formMessages, 'forms messages match');
});

t.test('with multiple modules', function (st) {
st.plan(3);
deprecations('forms', 'object.assign').then(function (messages) {
st.deepEqual(compact(messages.forms), compact(formMessages), 'forms messages match');
st.deepEqual(Object.keys(messages), ['forms', 'object.assign'], 'messages has two expected keys');
st.deepEqual(compact(messages['object.assign']), {
'0.1.0': 'Please upgrade to the latest spec-compliant version',
'0.1.1': 'Please upgrade to the latest spec-compliant version',
'0.2.0': 'Please upgrade to the latest spec-compliant version',
'0.2.1': 'Please upgrade to the latest spec-compliant version',
'0.3.1': 'Object.assign should accept any value except null and undefined, and should coerce to an object',
'0.4.0': 'Please update to the latest version',
'0.4.2': 'v0.4.3 doesn\'t modify function arguments, since it deoptimizes v8'
}, 'object.assign messages match');
}).then(null, st.fail);
t.test('with multiple modules', async (st) => {
const messages = await deprecations('forms', 'object.assign');

st.deepEqual(compact(messages.forms), compact(formMessages), 'forms messages match');
st.deepEqual(Object.keys(messages), ['forms', 'object.assign'], 'messages has two expected keys');
st.deepEqual(compact(messages['object.assign']), {
'0.1.0': 'Please upgrade to the latest spec-compliant version',
'0.1.1': 'Please upgrade to the latest spec-compliant version',
'0.2.0': 'Please upgrade to the latest spec-compliant version',
'0.2.1': 'Please upgrade to the latest spec-compliant version',
'0.3.1': 'Object.assign should accept any value except null and undefined, and should coerce to an object',
'0.4.0': 'Please update to the latest version',
'0.4.2': 'v0.4.3 doesn\'t modify function arguments, since it deoptimizes v8',
}, 'object.assign messages match');
});
});
38 changes: 19 additions & 19 deletions test/messages.js
Original file line number Diff line number Diff line change
@@ -1,29 +1,29 @@
'use strict';

var test = require('tape');
const test = require('tape');

var getMessages = require('../messages');
var Promise = require('../promise');
var versions = ['0.1.0', '0.2.0', '0.3.0'];
const getMessages = require('../messages');

var name = 'forms';
const versions = ['0.1.0', '0.2.0', '0.3.0'];
const name = 'forms';

test('returns a promise', async (t) => {
const promise = getMessages(name, versions);

test('returns a promise', function (t) {
t.plan(1);
var promise = getMessages(name, versions);
t.ok(promise instanceof Promise, 'returns a promise');

return promise;
});

test('gets deprecation messages', function (t) {
var promise = getMessages(name, versions);
var expected = [
{ '0.1.0': 'Please update to the latest version to ensure the latest security fixes in "qs"' },
{ '0.2.0': 'Please update to the latest version to ensure the latest security fixes in "qs"' },
{ '0.3.0': 'Please update to the latest version to ensure the latest security fixes in "qs"' }
];
t.plan(1);
promise.then(function (messages) {
t.deepEqual(messages, expected);
}, t.fail);
test('gets deprecation messages', async (t) => {
const expected = {
'0.1.0': 'Please update to the latest version to ensure the latest security fixes in "qs"',
'0.2.0': 'Please update to the latest version to ensure the latest security fixes in "qs"',
'0.3.0': 'Please update to the latest version to ensure the latest security fixes in "qs"',
};

const messages = await getMessages(name, versions);

t.deepEqual(messages, expected);
});

Loading

0 comments on commit 46c72d7

Please sign in to comment.