Skip to content

Commit

Permalink
refactor(esm): converted the package to esm
Browse files Browse the repository at this point in the history
BREAKING CHANGE: `@semantic-release/npm` is now a native ES Module. It
has named exports for each plugin hook (`verifyConditions`, `prepare`,
`publish`, `addChannel`)
  • Loading branch information
travi authored and gr2m committed Jan 13, 2023
1 parent 7157d76 commit 2d8ff15
Show file tree
Hide file tree
Showing 25 changed files with 2,363 additions and 4,443 deletions.
30 changes: 14 additions & 16 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
const {defaultTo, castArray} = require('lodash');
const AggregateError = require('aggregate-error');
const tempy = require('tempy');
const setLegacyToken = require('./lib/set-legacy-token');
const getPkg = require('./lib/get-pkg');
const verifyNpmConfig = require('./lib/verify-config');
const verifyNpmAuth = require('./lib/verify-auth');
const addChannelNpm = require('./lib/add-channel');
const prepareNpm = require('./lib/prepare');
const publishNpm = require('./lib/publish');
import { castArray, defaultTo } from 'lodash-es';
import AggregateError from 'aggregate-error';
import tempy from 'tempy';
import setLegacyToken from './lib/set-legacy-token.js';
import getPkg from './lib/get-pkg.js';
import verifyNpmConfig from './lib/verify-config.js';
import verifyNpmAuth from './lib/verify-auth.js';
import addChannelNpm from './lib/add-channel.js';
import prepareNpm from './lib/prepare.js';
import publishNpm from './lib/publish.js';

let verified;
let prepared;
const npmrc = tempy.file({name: '.npmrc'});

async function verifyConditions(pluginConfig, context) {
export async function verifyConditions(pluginConfig, context) {
// If the npm publish plugin is used and has `npmPublish`, `tarballDir` or `pkgRoot` configured, validate them now in order to prevent any release if the configuration is wrong
if (context.options.publish) {
const publishPlugin =
Expand Down Expand Up @@ -46,7 +46,7 @@ async function verifyConditions(pluginConfig, context) {
verified = true;
}

async function prepare(pluginConfig, context) {
export async function prepare(pluginConfig, context) {
const errors = verified ? [] : verifyNpmConfig(pluginConfig);

setLegacyToken(context);
Expand All @@ -69,7 +69,7 @@ async function prepare(pluginConfig, context) {
prepared = true;
}

async function publish(pluginConfig, context) {
export async function publish(pluginConfig, context) {
let pkg;
const errors = verified ? [] : verifyNpmConfig(pluginConfig);

Expand All @@ -96,7 +96,7 @@ async function publish(pluginConfig, context) {
return publishNpm(npmrc, pluginConfig, pkg, context);
}

async function addChannel(pluginConfig, context) {
export async function addChannel(pluginConfig, context) {
let pkg;
const errors = verified ? [] : verifyNpmConfig(pluginConfig);

Expand All @@ -118,5 +118,3 @@ async function addChannel(pluginConfig, context) {

return addChannelNpm(npmrc, pluginConfig, pkg, context);
}

module.exports = {verifyConditions, prepare, publish, addChannel};
12 changes: 6 additions & 6 deletions lib/add-channel.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
const execa = require('execa');
const getRegistry = require('./get-registry');
const getChannel = require('./get-channel');
const getReleaseInfo = require('./get-release-info');
import execa from 'execa';
import getRegistry from './get-registry.js';
import getChannel from './get-channel.js';
import getReleaseInfo from './get-release-info.js';

module.exports = async (npmrc, {npmPublish}, pkg, context) => {
export default async function (npmrc, {npmPublish}, pkg, context) {
const {
cwd,
env,
Expand Down Expand Up @@ -43,4 +43,4 @@ module.exports = async (npmrc, {npmPublish}, pkg, context) => {
);

return false;
};
}
56 changes: 39 additions & 17 deletions lib/definitions/errors.js
Original file line number Diff line number Diff line change
@@ -1,36 +1,52 @@
const pkg = require('../../package.json');
import {dirname, resolve} from 'node:path';
import {fileURLToPath} from 'node:url';
import {readPackageSync} from 'read-pkg';

const __dirname = dirname(fileURLToPath(import.meta.url));
const pkg = readPackageSync({cwd: resolve(__dirname, '../../')});
const [homepage] = pkg.homepage.split('#');
const linkify = (file) => `${homepage}/blob/master/${file}`;

module.exports = {
EINVALIDNPMPUBLISH: ({npmPublish}) => ({
export function EINVALIDNPMPUBLISH({ npmPublish }) {
return {
message: 'Invalid `npmPublish` option.',
details: `The [npmPublish option](${linkify('README.md#npmpublish')}) option, if defined, must be a \`Boolean\`.
Your configuration for the \`npmPublish\` option is \`${npmPublish}\`.`,
}),
EINVALIDTARBALLDIR: ({tarballDir}) => ({
};
}

export function EINVALIDTARBALLDIR({ tarballDir }) {
return {
message: 'Invalid `tarballDir` option.',
details: `The [tarballDir option](${linkify('README.md#tarballdir')}) option, if defined, must be a \`String\`.
Your configuration for the \`tarballDir\` option is \`${tarballDir}\`.`,
}),
EINVALIDPKGROOT: ({pkgRoot}) => ({
};
}

export function EINVALIDPKGROOT({ pkgRoot }) {
return {
message: 'Invalid `pkgRoot` option.',
details: `The [pkgRoot option](${linkify('README.md#pkgroot')}) option, if defined, must be a \`String\`.
Your configuration for the \`pkgRoot\` option is \`${pkgRoot}\`.`,
}),
ENONPMTOKEN: ({registry}) => ({
};
}

export function ENONPMTOKEN({ registry }) {
return {
message: 'No npm token specified.',
details: `An [npm token](${linkify(
'README.md#npm-registry-authentication'
)}) must be created and set in the \`NPM_TOKEN\` environment variable on your CI environment.
Please make sure to create an [npm token](https://docs.npmjs.com/getting-started/working_with_tokens#how-to-create-new-tokens) and to set it in the \`NPM_TOKEN\` environment variable on your CI environment. The token must allow to publish to the registry \`${registry}\`.`,
}),
EINVALIDNPMTOKEN: ({registry}) => ({
};
}

export function EINVALIDNPMTOKEN({ registry }) {
return {
message: 'Invalid npm token.',
details: `The [npm token](${linkify(
'README.md#npm-registry-authentication'
Expand All @@ -40,17 +56,23 @@ If you are using Two Factor Authentication for your account, set its level to ["
Authorization and writes" level.
Please make sure to set the \`NPM_TOKEN\` environment variable in your CI with the exact value of the npm token.`,
}),
ENOPKGNAME: () => ({
};
}

export function ENOPKGNAME() {
return {
message: 'Missing `name` property in `package.json`.',
details: `The \`package.json\`'s [name](https://docs.npmjs.com/files/package.json#name) property is required in order to publish a package to the npm registry.
Please make sure to add a valid \`name\` for your package in your \`package.json\`.`,
}),
ENOPKG: () => ({
};
}

export function ENOPKG() {
return {
message: 'Missing `package.json` file.',
details: `A [package.json file](https://docs.npmjs.com/files/package.json) at the root of your project is required to release on npm.
Please follow the [npm guideline](https://docs.npmjs.com/getting-started/creating-node-modules) to create a valid \`package.json\` file.`,
}),
};
};
}
6 changes: 4 additions & 2 deletions lib/get-channel.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
const semver = require('semver');
import semver from 'semver';

module.exports = (channel) => (channel ? (semver.validRange(channel) ? `release-${channel}` : channel) : 'latest');
export default function (channel) {
return channel ? (semver.validRange(channel) ? `release-${channel}` : channel) : 'latest';
}
9 changes: 5 additions & 4 deletions lib/get-error.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
const SemanticReleaseError = require('@semantic-release/error');
const ERROR_DEFINITIONS = require('./definitions/errors');
import SemanticReleaseError from '@semantic-release/error';
import * as ERROR_DEFINITIONS from './definitions/errors.js';

module.exports = (code, ctx = {}) => {
export default function (code, ctx = {}) {
const {message, details} = ERROR_DEFINITIONS[code](ctx);

return new SemanticReleaseError(message, code, details);
};
}
14 changes: 7 additions & 7 deletions lib/get-pkg.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
const path = require('path');
const readPkg = require('read-pkg');
const AggregateError = require('aggregate-error');
const getError = require('./get-error');
import path from 'path';
import {readPackage} from 'read-pkg';
import AggregateError from 'aggregate-error';
import getError from './get-error.js';

module.exports = async ({pkgRoot}, {cwd}) => {
export default async function ({pkgRoot}, {cwd}) {
try {
const pkg = await readPkg({cwd: pkgRoot ? path.resolve(cwd, String(pkgRoot)) : cwd});
const pkg = await readPackage({cwd: pkgRoot ? path.resolve(cwd, String(pkgRoot)) : cwd});

if (!pkg.name) {
throw getError('ENOPKGNAME');
Expand All @@ -19,4 +19,4 @@ module.exports = async ({pkgRoot}, {cwd}) => {

throw new AggregateError([error]);
}
};
}
29 changes: 15 additions & 14 deletions lib/get-registry.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
const path = require('path');
const rc = require('rc');
const getRegistryUrl = require('registry-auth-token/registry-url');
import path from 'path';
import rc from 'rc';
import getRegistryUrl from 'registry-auth-token/registry-url.js';

module.exports = ({publishConfig: {registry} = {}, name}, {cwd, env}) =>
registry ||
env.NPM_CONFIG_REGISTRY ||
getRegistryUrl(
name.split('/')[0],
rc(
'npm',
{registry: 'https://registry.npmjs.org/'},
{config: env.NPM_CONFIG_USERCONFIG || path.resolve(cwd, '.npmrc')}
)
);
export default function ({ publishConfig: { registry } = {}, name }, { cwd, env }) {
return registry ||
env.NPM_CONFIG_REGISTRY ||
getRegistryUrl(
name.split('/')[0],
rc(
'npm',
{ registry: 'https://registry.npmjs.org/' },
{ config: env.NPM_CONFIG_USERCONFIG || path.resolve(cwd, '.npmrc') }
)
);
}
16 changes: 9 additions & 7 deletions lib/get-release-info.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
const normalizeUrl = require('normalize-url');
import normalizeUrl from 'normalize-url';

module.exports = (
export default function (
{name},
{env: {DEFAULT_NPM_REGISTRY = 'https://registry.npmjs.org/'}, nextRelease: {version}},
distTag,
registry
) => ({
name: `npm package (@${distTag} dist-tag)`,
url:
) {
return {
name: `npm package (@${distTag} dist-tag)`,
url:
normalizeUrl(registry) === normalizeUrl(DEFAULT_NPM_REGISTRY)
? `https://www.npmjs.com/package/${name}/v/${version}`
: undefined,
channel: distTag,
});
channel: distTag,
};
}
8 changes: 4 additions & 4 deletions lib/prepare.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
const path = require('path');
const {move} = require('fs-extra');
const execa = require('execa');
import path from 'path';
import { move } from 'fs-extra';
import execa from 'execa';

module.exports = async (npmrc, {tarballDir, pkgRoot}, {cwd, env, stdout, stderr, nextRelease: {version}, logger}) => {
export default async function (npmrc, {tarballDir, pkgRoot}, {cwd, env, stdout, stderr, nextRelease: {version}, logger}) {
const basePath = pkgRoot ? path.resolve(cwd, pkgRoot) : cwd;

logger.log('Write version %s to package.json in %s', version, basePath);
Expand Down
14 changes: 7 additions & 7 deletions lib/publish.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
const path = require('path');
const execa = require('execa');
const getRegistry = require('./get-registry');
const getChannel = require('./get-channel');
const getReleaseInfo = require('./get-release-info');
import path from 'path';
import execa from 'execa';
import getRegistry from './get-registry.js';
import getChannel from './get-channel.js';
import getReleaseInfo from './get-release-info.js';

module.exports = async (npmrc, {npmPublish, pkgRoot}, pkg, context) => {
export default async function (npmrc, {npmPublish, pkgRoot}, pkg, context) {
const {
cwd,
env,
Expand Down Expand Up @@ -41,4 +41,4 @@ module.exports = async (npmrc, {npmPublish, pkgRoot}, pkg, context) => {
);

return false;
};
}
4 changes: 2 additions & 2 deletions lib/set-legacy-token.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module.exports = ({env}) => {
export default function ({env}) {
// Set the environment variable `LEGACY_TOKEN` when user use the legacy auth, so it can be resolved by npm CLI
if (env.NPM_USERNAME && env.NPM_PASSWORD && env.NPM_EMAIL) {
env.LEGACY_TOKEN = Buffer.from(`${env.NPM_USERNAME}:${env.NPM_PASSWORD}`, 'utf8').toString('base64');
}
};
}
28 changes: 14 additions & 14 deletions lib/set-npmrc-auth.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
const path = require('path');
const rc = require('rc');
const {outputFile, readFile} = require('fs-extra');
const getAuthToken = require('registry-auth-token');
const nerfDart = require('nerf-dart');
const AggregateError = require('aggregate-error');
const getError = require('./get-error');
import path from 'path';
import rc from 'rc';
import fs from 'fs-extra';
import getAuthToken from 'registry-auth-token';
import nerfDart from 'nerf-dart';
import AggregateError from 'aggregate-error';
import getError from './get-error.js';

module.exports = async (
export default async function (
npmrc,
registry,
{cwd, env: {NPM_TOKEN, NPM_CONFIG_USERCONFIG, NPM_USERNAME, NPM_PASSWORD, NPM_EMAIL}, logger}
) => {
) {
logger.log('Verify authentication for registry %s', registry);
const {configs, ...rcConfig} = rc(
'npm',
Expand All @@ -22,26 +22,26 @@ module.exports = async (
logger.log('Reading npm config from %s', configs.join(', '));
}

const currentConfig = configs ? (await Promise.all(configs.map((config) => readFile(config)))).join('\n') : '';
const currentConfig = configs ? (await Promise.all(configs.map((config) => fs.readFile(config)))).join('\n') : '';

if (getAuthToken(registry, {npmrc: rcConfig})) {
await outputFile(npmrc, currentConfig);
await fs.outputFile(npmrc, currentConfig);
return;
}

if (NPM_USERNAME && NPM_PASSWORD && NPM_EMAIL) {
await outputFile(
await fs.outputFile(
npmrc,
`${currentConfig ? `${currentConfig}\n` : ''}_auth = \${LEGACY_TOKEN}\nemail = \${NPM_EMAIL}`
);
logger.log(`Wrote NPM_USERNAME, NPM_PASSWORD and NPM_EMAIL to ${npmrc}`);
} else if (NPM_TOKEN) {
await outputFile(
await fs.outputFile(
npmrc,
`${currentConfig ? `${currentConfig}\n` : ''}${nerfDart(registry)}:_authToken = \${NPM_TOKEN}`
);
logger.log(`Wrote NPM_TOKEN to ${npmrc}`);
} else {
throw new AggregateError([getError('ENONPMTOKEN', {registry})]);
}
};
}
Loading

0 comments on commit 2d8ff15

Please sign in to comment.