Skip to content

Commit

Permalink
feat: add custom npm registry when installing dependencies (#994)
Browse files Browse the repository at this point in the history
  • Loading branch information
easymikey authored Dec 16, 2024
1 parent 7c08fe0 commit fb436fa
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 12 deletions.
2 changes: 2 additions & 0 deletions man/zx.1
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ evaluate script
default extension
.SS --install, -i
install dependencies
.SS --registry<URL>
npm registry, defaults to https://registry.npmjs.org/
.SS --repl
start repl
.SS --version, -v
Expand Down
6 changes: 4 additions & 2 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ export function printUsage() {
--eval=<js>, -e evaluate script
--ext=<.mjs> default extension
--install, -i install dependencies
--registry=<URL> npm registry, defaults to https://registry.npmjs.org/
--version, -v print current zx version
--help, -h print help
--repl start repl
Expand All @@ -70,7 +71,7 @@ export function printUsage() {
}

export const argv: minimist.ParsedArgs = minimist(process.argv.slice(2), {
string: ['shell', 'prefix', 'postfix', 'eval', 'cwd', 'ext'],
string: ['shell', 'prefix', 'postfix', 'eval', 'cwd', 'ext', 'registry'],
boolean: [
'version',
'help',
Expand Down Expand Up @@ -206,8 +207,9 @@ export async function importPath(
}
if (argv.install) {
const deps = parseDeps(await fs.readFile(filepath))
await installDeps(deps, dir)
await installDeps(deps, dir, argv.registry)
}

injectGlobalRequire(origin)
// TODO: fix unanalyzable-dynamic-import to work correctly with jsr.io
await import(url.pathToFileURL(filepath).toString())
Expand Down
16 changes: 12 additions & 4 deletions src/deps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,27 @@ import { $ } from './core.js'
import { spinner } from './goods.js'
import { depseek } from './vendor.js'

/**
* Install npm dependencies
* @param dependencies object of dependencies
* @param prefix path to the directory where npm should install the dependencies
* @param registry custom npm registry URL when installing dependencies
*/
export async function installDeps(
dependencies: Record<string, string>,
prefix?: string
) {
const flags = prefix ? `--prefix=${prefix}` : ''
prefix?: string,
registry?: string
): Promise<void> {
const prefixFlag = prefix ? `--prefix=${prefix}` : ''
const registryFlag = registry ? `--registry=${registry}` : ''
const packages = Object.entries(dependencies).map(
([name, version]) => `${name}@${version}`
)
if (packages.length === 0) {
return
}
await spinner(`npm i ${packages.join(' ')}`, () =>
$`npm install --no-save --no-audit --no-fund ${flags} ${packages}`.nothrow()
$`npm install --no-save --no-audit --no-fund ${registryFlag} ${prefixFlag} ${packages}`.nothrow()
)
}

Expand Down
39 changes: 33 additions & 6 deletions test/deps.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
// limitations under the License.

import assert from 'node:assert'
import { test, describe, before, beforeEach } from 'node:test'
import { $ } from '../build/index.js'
import { test, describe } from 'node:test'
import { $, tmpfile, fs } from '../build/index.js'
import { installDeps, parseDeps } from '../build/deps.js'

describe('deps', () => {
Expand All @@ -27,12 +27,39 @@ describe('deps', () => {
assert((await import('lodash-es')).pick instanceof Function)
})

test('installDeps() loader works via JS API with custom npm registry URL', async () => {
await installDeps(
{
'@jsr/std__internal': '1.0.5',
},
undefined,
'https://npm.jsr.io'
)

assert((await import('@jsr/std__internal')).diff instanceof Function)
})

test('installDeps() loader works via CLI', async () => {
const out =
await $`node build/cli.js --install <<< 'import _ from "lodash" /* @4.17.15 */; console.log(_.VERSION)'`
assert.match(out.stdout, /4.17.15/)
})

test('installDeps() loader works via CLI with custom npm registry URL', async () => {
const code =
'import { diff } from "@jsr/std__internal";console.log(diff instanceof Function)'
const file = tmpfile('index.mjs', code)

let out =
await $`node build/cli.js --i --registry=https://npm.jsr.io ${file}`
fs.remove(file)
assert.match(out.stdout, /true/)

out =
await $`node build/cli.js -i --registry=https://npm.jsr.io <<< ${code}`
assert.match(out.stdout, /true/)
})

test('parseDeps(): import or require', async () => {
;[
[`import "foo"`, { foo: 'latest' }],
Expand Down Expand Up @@ -82,11 +109,11 @@ describe('deps', () => {
require('a') // @1.0.0
const b =require('b') /* @2.0.0 */
const c = {
c:require('c') /* @3.0.0 */,
d: await import('d') /* @4.0.0 */,
c:require('c') /* @3.0.0 */,
d: await import('d') /* @4.0.0 */,
...require('e') /* @5.0.0 */
}
const f = [...require('f') /* @6.0.0 */]
const f = [...require('f') /* @6.0.0 */]
;require('g'); // @7.0.0
const h = 1 *require('h') // @8.0.0
{require('i') /* @9.0.0 */}
Expand All @@ -96,7 +123,7 @@ describe('deps', () => {
import path from 'path'
import foo from "foo"
// import aaa from 'a'
/* import bbb from 'b' */
/* import bbb from 'b' */
import bar from "bar" /* @1.0.0 */
import baz from "baz" // @^2.0
import qux from "@qux/pkg/entry" // @^3.0
Expand Down

0 comments on commit fb436fa

Please sign in to comment.