npx-import
Advanced tools
Comparing version 1.0.5-0 to 1.1.0
@@ -0,7 +1,9 @@ | ||
import os from 'node:os'; | ||
import path from 'node:path'; | ||
import semver from 'semver'; | ||
import path from 'path'; | ||
import { parse } from 'parse-package-name'; | ||
import { _import, _importRelative, _resolve, _resolveRelative } from './utils.js'; | ||
import { execaCommand } from 'execa'; | ||
import validateNpmName from 'validate-npm-package-name'; | ||
import { _import, _importRelative, _resolve, _resolveRelative } from './utils.js'; | ||
const WINDOWS = os.platform() === 'win32'; | ||
const NOT_IMPORTABLE = Symbol(); | ||
@@ -105,4 +107,4 @@ const INSTALLED_LOCALLY = Symbol(); | ||
} | ||
if (!semver.gte(npmVersion, '7.0.0')) { | ||
throw new Error(`Require npm version 7+. Got '${npmVersion}' when running '${versionCmd}'`); | ||
if (!semver.gte(npmVersion, '8.0.0')) { | ||
throw new Error(`Require npm version 8+. Got '${npmVersion}' when running '${versionCmd}'`); | ||
} | ||
@@ -116,5 +118,5 @@ } | ||
logger(`Installing... (${installPackage})`); | ||
const emitPath = `node -e 'console.log(process.env.PATH)'`; | ||
const emitPath = WINDOWS ? `set PATH` : `printenv PATH`; | ||
const fullCmd = `${installPackage} ${emitPath}`; | ||
const { failed, stdout, stderr } = await execaCommand(fullCmd, { | ||
const { failed, stdout } = await execaCommand(fullCmd, { | ||
shell: true, | ||
@@ -125,16 +127,3 @@ }); | ||
} | ||
const paths = stdout.split(':'); | ||
const tempPath = paths.find((p) => /\/\.npm\/_npx\//.exec(p)); | ||
if (!tempPath) { | ||
console.log({ stdout }); | ||
console.log({ stderr }); | ||
console.log({ paths }); | ||
const { stdout: env } = await execaCommand(`node -e 'console.log(JSON.stringify(process.env))`, { | ||
shell: true, | ||
}); | ||
console.log({ env }); | ||
const { stdout: env2 } = await execaCommand(`node -e 'console.log(JSON.stringify(process.env))`); | ||
console.log({ env2 }); | ||
throw new Error(`Failed to find temporary install directory. Looking for paths matching '/.npm/_npx/' in:\n${JSON.stringify(paths)}`); | ||
} | ||
const tempPath = getTempPath(stdout); | ||
// Expecting the path ends with node_modules/.bin | ||
@@ -188,1 +177,18 @@ const nodeModulesPath = path.resolve(tempPath, '..'); | ||
}; | ||
// Find where NPX just installed the package | ||
function getTempPath(stdout) { | ||
if (WINDOWS) { | ||
const paths = stdout.replace(/^PATH=/i, '').split(';'); | ||
const tempPath = paths.find((p) => /\\npm-cache\\_npx\\/.exec(p)); | ||
if (!tempPath) | ||
throw new Error(`Failed to find temporary install directory. Looking for paths matching '\\npm-cache\\_npx\\' in:\n${JSON.stringify(paths)}`); | ||
return tempPath; | ||
} | ||
else { | ||
const paths = stdout.split(':'); | ||
const tempPath = paths.find((p) => /\/\.npm\/_npx\//.exec(p)); | ||
if (!tempPath) | ||
throw new Error(`Failed to find temporary install directory. Looking for paths matching '/.npm/_npx/' in:\n${JSON.stringify(paths)}`); | ||
return tempPath; | ||
} | ||
} |
/* The purpose of this file is to be mocked for testing. */ | ||
import { createRequire } from 'module'; | ||
import { pathToFileURL } from 'node:url'; | ||
import { createRequire } from 'node:module'; | ||
export async function _import(packageWithPath) { | ||
@@ -7,3 +8,3 @@ return await import(packageWithPath); | ||
export async function _importRelative(installDir, packageWithPath) { | ||
return await import(_resolveRelative(installDir, packageWithPath)); | ||
return await import(pathToFileURL(_resolveRelative(installDir, packageWithPath)).href); | ||
} | ||
@@ -14,3 +15,3 @@ export function _resolve(packageWithPath) { | ||
export function _resolveRelative(installDir, packageWithPath) { | ||
return createRequire(installDir).resolve(packageWithPath); | ||
return createRequire(pathToFileURL(installDir).href).resolve(packageWithPath); | ||
} |
{ | ||
"name": "npx-import", | ||
"version": "1.0.5-0", | ||
"version": "1.1.0", | ||
"description": "Runtime dependencies, installed as if by magic ✨", | ||
@@ -5,0 +5,0 @@ "main": "lib/index.js", |
@@ -0,8 +1,11 @@ | ||
import os from 'node:os' | ||
import path from 'node:path' | ||
import semver from 'semver' | ||
import path from 'path' | ||
import { parse } from 'parse-package-name' | ||
import { _import, _importRelative, _resolve, _resolveRelative } from './utils.js' | ||
import { execaCommand } from 'execa' | ||
import validateNpmName from 'validate-npm-package-name' | ||
import { _import, _importRelative, _resolve, _resolveRelative } from './utils.js' | ||
const WINDOWS = os.platform() === 'win32' | ||
type Logger = (message: string) => void | ||
@@ -150,5 +153,5 @@ | ||
logger(`Installing... (${installPackage})`) | ||
const emitPath = `node -e 'console.log(process.env.PATH)'` | ||
const emitPath = WINDOWS ? `set PATH` : `printenv PATH` | ||
const fullCmd = `${installPackage} ${emitPath}` | ||
const { failed, stdout, stderr } = await execaCommand(fullCmd, { | ||
const { failed, stdout } = await execaCommand(fullCmd, { | ||
shell: true, | ||
@@ -161,26 +164,4 @@ }) | ||
} | ||
const paths = stdout.split(':') | ||
const tempPath = paths.find((p) => /\/\.npm\/_npx\//.exec(p)) | ||
const tempPath = getTempPath(stdout) | ||
if (!tempPath) { | ||
console.log({ stdout }) | ||
console.log({ stderr }) | ||
console.log({ paths }) | ||
const { stdout: env } = await execaCommand( | ||
`node -e 'console.log(JSON.stringify(process.env))`, | ||
{ | ||
shell: true, | ||
} | ||
) | ||
console.log({ env }) | ||
const { stdout: env2 } = await execaCommand(`node -e 'console.log(JSON.stringify(process.env))`) | ||
console.log({ env2 }) | ||
throw new Error( | ||
`Failed to find temporary install directory. Looking for paths matching '/.npm/_npx/' in:\n${JSON.stringify( | ||
paths | ||
)}` | ||
) | ||
} | ||
// Expecting the path ends with node_modules/.bin | ||
@@ -237,1 +218,28 @@ const nodeModulesPath = path.resolve(tempPath, '..') | ||
} | ||
// Find where NPX just installed the package | ||
function getTempPath(stdout: string) { | ||
if (WINDOWS) { | ||
const paths = stdout.replace(/^PATH=/i, '').split(';') | ||
const tempPath = paths.find((p) => /\\npm-cache\\_npx\\/.exec(p)) | ||
if (!tempPath) | ||
throw new Error( | ||
`Failed to find temporary install directory. Looking for paths matching '\\npm-cache\\_npx\\' in:\n${JSON.stringify( | ||
paths | ||
)}` | ||
) | ||
return tempPath | ||
} else { | ||
const paths = stdout.split(':') | ||
const tempPath = paths.find((p) => /\/\.npm\/_npx\//.exec(p)) | ||
if (!tempPath) | ||
throw new Error( | ||
`Failed to find temporary install directory. Looking for paths matching '/.npm/_npx/' in:\n${JSON.stringify( | ||
paths | ||
)}` | ||
) | ||
return tempPath | ||
} | ||
} |
/* The purpose of this file is to be mocked for testing. */ | ||
import { createRequire } from 'module' | ||
import { pathToFileURL } from 'node:url' | ||
import { createRequire } from 'node:module' | ||
@@ -9,3 +10,3 @@ export async function _import(packageWithPath: string) { | ||
export async function _importRelative(installDir: string, packageWithPath: string) { | ||
return await import(_resolveRelative(installDir, packageWithPath)) | ||
return await import(pathToFileURL(_resolveRelative(installDir, packageWithPath)).href) | ||
} | ||
@@ -18,3 +19,3 @@ | ||
export function _resolveRelative(installDir: string, packageWithPath: string) { | ||
return createRequire(installDir).resolve(packageWithPath) | ||
return createRequire(pathToFileURL(installDir).href).resolve(packageWithPath) | ||
} |
@@ -16,2 +16,4 @@ import { afterEach, describe, expect, test, vi } from 'vitest' | ||
pkgParseFailed, | ||
getBasePath, | ||
printPathCmd, | ||
} from './utils' | ||
@@ -165,6 +167,5 @@ import { npxImport, npxResolve } from '../lib' | ||
expectExecaCommand('npx --version').returning({ stdout: '8.1.2' }) | ||
expectExecaCommand( | ||
`npx --prefer-online -y -p broken-install@^2.0.0 node -e 'console.log(process.env.PATH)'`, | ||
{ shell: true } | ||
).returning(new Error('EXPLODED TRYING TO INSTALL')) | ||
expectExecaCommand(`npx --prefer-online -y -p broken-install@^2.0.0 ${printPathCmd}`, { | ||
shell: true, | ||
}).returning(new Error('EXPLODED TRYING TO INSTALL')) | ||
@@ -183,6 +184,5 @@ await npxImportFailed( | ||
expectExecaCommand('npx --version').returning({ stdout: '8.1.2' }) | ||
expectExecaCommand( | ||
`npx --prefer-online -y -p left-pad@this-tag-no-exist node -e 'console.log(process.env.PATH)'`, | ||
{ shell: true } | ||
).returning(new Error('No matching version found for left-pad@this-tag-no-exist.')) | ||
expectExecaCommand(`npx --prefer-online -y -p left-pad@this-tag-no-exist ${printPathCmd}`, { | ||
shell: true, | ||
}).returning(new Error('No matching version found for left-pad@this-tag-no-exist.')) | ||
@@ -201,6 +201,6 @@ await npxImportFailed( | ||
const npxDirectoryHash = randomString(12) | ||
const basePath = `/Users/glen/.npm/_npx/${npxDirectoryHash}/node_modules` | ||
const basePath = getBasePath(npxDirectoryHash) | ||
expectExecaCommand('npx --version').returning({ stdout: '8.1.2' }) | ||
expectExecaCommand(`npx --prefer-online -y -p @org/pkg@my-tag node -e 'console.log(process.env.PATH)'`, { | ||
expectExecaCommand(`npx --prefer-online -y -p @org/pkg@my-tag ${printPathCmd}`, { | ||
shell: true, | ||
@@ -226,6 +226,6 @@ }).returning({ stdout: getNpxPath(npxDirectoryHash) }) | ||
const npxDirectoryHash = randomString(12) | ||
const basePath = `/Users/glen/.npm/_npx/${npxDirectoryHash}/node_modules` | ||
const basePath = getBasePath(npxDirectoryHash) | ||
expectExecaCommand('npx --version').returning({ stdout: '8.1.2' }) | ||
expectExecaCommand(`npx --prefer-online -y -p @org/pkg@my-tag node -e 'console.log(process.env.PATH)'`, { | ||
expectExecaCommand(`npx --prefer-online -y -p @org/pkg@my-tag ${printPathCmd}`, { | ||
shell: true, | ||
@@ -249,6 +249,6 @@ }).returning({ stdout: getNpxPath(npxDirectoryHash) }) | ||
const npxDirectoryHash = randomString(12) | ||
const basePath = `/Users/glen/.npm/_npx/${npxDirectoryHash}/node_modules` | ||
const basePath = getBasePath(npxDirectoryHash) | ||
expectExecaCommand('npx --version').returning({ stdout: '8.1.2' }) | ||
expectExecaCommand(`npx --prefer-offline -y -p @org/pkg@3.0.1 node -e 'console.log(process.env.PATH)'`, { | ||
expectExecaCommand(`npx --prefer-offline -y -p @org/pkg@3.0.1 ${printPathCmd}`, { | ||
shell: true, | ||
@@ -272,11 +272,8 @@ }).returning({ stdout: getNpxPath(npxDirectoryHash) }) | ||
const npxDirectoryHash = randomString(12) | ||
const basePath = `/Users/glen/.npm/_npx/${npxDirectoryHash}/node_modules` | ||
const basePath = getBasePath(npxDirectoryHash) | ||
expectExecaCommand('npx --version').returning({ stdout: '8.1.2' }) | ||
expectExecaCommand( | ||
`npx --prefer-online -y -p pkg-a@latest -p pkg-b@latest node -e 'console.log(process.env.PATH)'`, | ||
{ | ||
shell: true, | ||
} | ||
).returning({ stdout: getNpxPath(npxDirectoryHash) }) | ||
expectExecaCommand(`npx --prefer-online -y -p pkg-a@latest -p pkg-b@latest ${printPathCmd}`, { | ||
shell: true, | ||
}).returning({ stdout: getNpxPath(npxDirectoryHash) }) | ||
expectRelativeImport(basePath, 'pkg-a').returning({ name: 'pkg-a', foo: 1 }) | ||
@@ -305,6 +302,6 @@ expectRelativeImport(basePath, 'pkg-b').returning({ name: 'pkg-b', bar: 2 }) | ||
const npxDirectoryHash = randomString(12) | ||
const basePath = `/Users/glen/.npm/_npx/${npxDirectoryHash}/node_modules` | ||
const basePath = getBasePath(npxDirectoryHash) | ||
expectExecaCommand('npx --version').returning({ stdout: '8.1.2' }) | ||
expectExecaCommand(`npx --prefer-offline -y -p pkg-b@1.2.3 node -e 'console.log(process.env.PATH)'`, { | ||
expectExecaCommand(`npx --prefer-offline -y -p pkg-b@1.2.3 ${printPathCmd}`, { | ||
shell: true, | ||
@@ -334,11 +331,8 @@ }).returning({ stdout: getNpxPath(npxDirectoryHash) }) | ||
const npxDirectoryHash = randomString(12) | ||
const basePath = `/Users/glen/.npm/_npx/${npxDirectoryHash}/node_modules` | ||
const basePath = getBasePath(npxDirectoryHash) | ||
expectExecaCommand('npx --version').returning({ stdout: '8.1.2' }) | ||
expectExecaCommand( | ||
`npx --prefer-online -y -p 'pkg-a@>1.0.0' -p 'pkg-b@*' node -e 'console.log(process.env.PATH)'`, | ||
{ | ||
shell: true, | ||
} | ||
).returning({ stdout: getNpxPath(npxDirectoryHash) }) | ||
expectExecaCommand(`npx --prefer-online -y -p 'pkg-a@>1.0.0' -p 'pkg-b@*' ${printPathCmd}`, { | ||
shell: true, | ||
}).returning({ stdout: getNpxPath(npxDirectoryHash) }) | ||
expectRelativeImport(basePath, 'pkg-a').returning({ name: 'pkg-a', foo: 1 }) | ||
@@ -372,3 +366,3 @@ expectRelativeImport(basePath, 'pkg-b').returning({ name: 'pkg-b', bar: 2 }) | ||
const npxDirectoryHash = randomString(12) | ||
const basePath = `/Users/glen/.npm/_npx/${npxDirectoryHash}/node_modules` | ||
const basePath = getBasePath(npxDirectoryHash) | ||
@@ -379,3 +373,3 @@ _import.mockResolvedValueOnce({}) // pkg-a | ||
expectExecaCommand('npx --version').returning({ stdout: '8.1.2' }) | ||
expectExecaCommand(`npx --prefer-online -y -p pkg-b@latest node -e 'console.log(process.env.PATH)'`, { | ||
expectExecaCommand(`npx --prefer-online -y -p pkg-b@latest ${printPathCmd}`, { | ||
shell: true, | ||
@@ -382,0 +376,0 @@ }).returning({ stdout: getNpxPath(npxDirectoryHash) }) |
@@ -7,2 +7,5 @@ import { expect, MockedFunction } from 'vitest' | ||
import * as utils from '../lib/utils' | ||
import os from 'os' | ||
const WINDOWS = os.platform() === 'win32' | ||
export const printPathCmd = WINDOWS ? 'set PATH' : 'printenv PATH' | ||
@@ -115,4 +118,13 @@ const { _import, _importRelative, _resolve, _resolveRelative } = utils as unknown as { | ||
export function getNpxPath(npxDirectoryHash: string) { | ||
return `/my/local/pwd/node_modules/.bin:/my/local/node_modules/.bin:/my/node_modules/.bin:/node_modules/.bin:/Users/glen/.nvm/versions/node/v18.3.0/lib/node_modules/npm/node_modules/@npmcli/run-script/lib/node-gyp-bin:/Users/glen/.npm/_npx/${npxDirectoryHash}/node_modules/.bin:/Users/glen/go/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin:/usr/X11/bin:/usr/local/go/bin` | ||
export function getBasePath(randomHash: string) { | ||
return WINDOWS | ||
? `C:\\Users\\glen\\AppData\\Local\\npm-cache\\_npx\\${randomHash}\\node_modules` | ||
: `/Users/glen/.npm/_npx/${randomHash}/node_modules` | ||
} | ||
export function getNpxPath(randomHash: string) { | ||
return WINDOWS | ||
? `C:\\Users\\glen\\node_modules\\.bin;C:\\Users\\node_modules\\.bin;C:\\node_modules\\.bin;C:\\Program Files\\nodejs\\node_modules\\npm\\node_modules\\@npmcli\\run-script\\lib\\node-gyp-bin;C:\\Users\\glen\\AppData\\Local\\npm-cache\\_npx\\${randomHash}\\node_modules\\.bin;C:\\Users\\glen\\bin;C:\\Program Files\\Git\\mingw64\\bin;C:\\Program Files\\Git\\usr\\local\\bin;C:\\Program Files\\Git\\usr\\bin;C:\\Program Files\\Git\\usr\\bin;C:\\Program Files\\Git\\mingw64\\bin;C:\\Program Files\\Git\\usr\\bin;C:\\Users\\glen\\bin;C:\\Program Files (x86)\\Razer Chroma SDK\\bin;C:\\Program Files\\Razer Chroma SDK\\bin;C:\\Program Files (x86)\\Razer\\ChromaBroadcast\\bin;C:\\Program Files\\Razer\\ChromaBroadcast\\bin;C:\\Python38\\Scripts;C: | ||
Python38;C:\\Windows\\system32;C:\\Windows;C:\\Windows\\System32\\Wbem;C:\\Windows\\System32\\WindowsPowerShell\\v1.0;C:\\Windows\\System32\\OpenSSH;C:\\Program Files (x86)\\NVIDIA Corporation\\PhysX\\Common;C:\\WINDOWS\\system32;C:\\WINDOWS;C:\\WINDOWS\\System32\\Wbem;C:\\WINDOWS\\System32\\WindowsPowerShell\\v1.0;C:\\WINDOWS\\System32\\OpenSSH;C:\\Program Files\\nodejs;C:\\ProgramData\\chocolatey\\bin;C:\\Program Files\\dotnet;C:\\WINDOWS\\system32\\config\\systemprofile\\AppData\\Local\\Microsoft\\WindowsApps;C:\\Program Files\\Docker\\Docker\\resources\\bin;C:\\ProgramData\\DockerDesktop\\version-bin;C:\\Program Files\\NVIDIA Corporation\\NVIDIA NvDLISR;C:\\Program Files\\Cloudflare\\Cloudflare WARP;C:\\Program Files\\Git\\cmd;C:\\Users\\glen\\AppData\\Local\\Microsoft\\WindowsApps;C:\\Program Files (x86)\\Nmap;C:\\Program Files\\JetBrains\\WebStorm 2020.3\\bin;C:\\Users\\glen\\AppData\\Local\\Programs\\Microsoft VS Code\\bin;C:\\Users\\glen\\AppData\\Roaming\\npm;C:\\Program Files\\Git\\usr\\bin\\vendor_perl;C:\\Program Files\\Git\\usr\\bin\\core_perl` | ||
: `/my/local/pwd/node_modules/.bin:/my/local/node_modules/.bin:/my/node_modules/.bin:/node_modules/.bin:/Users/glen/.nvm/versions/node/v18.3.0/lib/node_modules/npm/node_modules/@npmcli/run-script/lib/node-gyp-bin:/Users/glen/.npm/_npx/${randomHash}/node_modules/.bin:/Users/glen/go/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin:/usr/X11/bin:/usr/local/go/bin` | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Debug access
Supply chain riskUses debug, reflection and dynamic code execution features.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
61144
924
0
4