Browse Source

experimental: support `package.json#engines` for `use` and `install` (#839)

Co-authored-by: Gal Schlezinger <gal@spitfire.co.il>
remotes/origin/list-filter
Amit Dahan 2 years ago committed by GitHub
parent
commit
97be792a44
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 5
      .changeset/warm-parrots-drive.md
  2. 91
      docs/commands.md
  3. 82
      e2e/__snapshots__/basic.test.ts.snap
  4. 28
      e2e/basic.test.ts
  5. 1
      e2e/env.test.ts
  6. 2
      e2e/shellcode/shells.ts
  7. 4
      e2e/shellcode/shells/cmdEnv.ts
  8. 1
      src/commands/env.rs
  9. 17
      src/config.rs
  10. 1
      src/main.rs
  11. 19
      src/package_json.rs
  12. 3
      src/user_version.rs
  13. 2
      src/user_version_reader.rs
  14. 59
      src/version_files.rs

5
.changeset/warm-parrots-drive.md

@ -0,0 +1,5 @@
---
"fnm": minor
---
Support resolving `engines.node` field via experimental `--resolve-engines` flag

91
docs/commands.md

@ -59,6 +59,13 @@ Options:
[env: FNM_COREPACK_ENABLED] [env: FNM_COREPACK_ENABLED]
--resolve-engines
Resolve `engines.node` field in `package.json` whenever a `.node-version` or `.nvmrc` file is not present.
Experimental: This feature is subject to change.
Note: `engines.node` can be any semver range, with the latest satisfying version being resolved.
[env: FNM_RESOLVE_ENGINES]
-h, --help -h, --help
Print help (see a summary with '-h') Print help (see a summary with '-h')
@ -112,6 +119,13 @@ Options:
[env: FNM_COREPACK_ENABLED] [env: FNM_COREPACK_ENABLED]
--resolve-engines
Resolve `engines.node` field in `package.json` whenever a `.node-version` or `.nvmrc` file is not present.
Experimental: This feature is subject to change.
Note: `engines.node` can be any semver range, with the latest satisfying version being resolved.
[env: FNM_RESOLVE_ENGINES]
-h, --help -h, --help
Print help (see a summary with '-h') Print help (see a summary with '-h')
``` ```
@ -162,6 +176,13 @@ Options:
[env: FNM_COREPACK_ENABLED] [env: FNM_COREPACK_ENABLED]
--resolve-engines
Resolve `engines.node` field in `package.json` whenever a `.node-version` or `.nvmrc` file is not present.
Experimental: This feature is subject to change.
Note: `engines.node` can be any semver range, with the latest satisfying version being resolved.
[env: FNM_RESOLVE_ENGINES]
-h, --help -h, --help
Print help (see a summary with '-h') Print help (see a summary with '-h')
``` ```
@ -222,6 +243,13 @@ Options:
[env: FNM_COREPACK_ENABLED] [env: FNM_COREPACK_ENABLED]
--resolve-engines
Resolve `engines.node` field in `package.json` whenever a `.node-version` or `.nvmrc` file is not present.
Experimental: This feature is subject to change.
Note: `engines.node` can be any semver range, with the latest satisfying version being resolved.
[env: FNM_RESOLVE_ENGINES]
-h, --help -h, --help
Print help (see a summary with '-h') Print help (see a summary with '-h')
``` ```
@ -282,6 +310,13 @@ Options:
[env: FNM_COREPACK_ENABLED] [env: FNM_COREPACK_ENABLED]
--resolve-engines
Resolve `engines.node` field in `package.json` whenever a `.node-version` or `.nvmrc` file is not present.
Experimental: This feature is subject to change.
Note: `engines.node` can be any semver range, with the latest satisfying version being resolved.
[env: FNM_RESOLVE_ENGINES]
-h, --help -h, --help
Print help (see a summary with '-h') Print help (see a summary with '-h')
``` ```
@ -347,6 +382,13 @@ Options:
[env: FNM_COREPACK_ENABLED] [env: FNM_COREPACK_ENABLED]
--resolve-engines
Resolve `engines.node` field in `package.json` whenever a `.node-version` or `.nvmrc` file is not present.
Experimental: This feature is subject to change.
Note: `engines.node` can be any semver range, with the latest satisfying version being resolved.
[env: FNM_RESOLVE_ENGINES]
-h, --help -h, --help
Print help (see a summary with '-h') Print help (see a summary with '-h')
``` ```
@ -402,6 +444,13 @@ Options:
[env: FNM_COREPACK_ENABLED] [env: FNM_COREPACK_ENABLED]
--resolve-engines
Resolve `engines.node` field in `package.json` whenever a `.node-version` or `.nvmrc` file is not present.
Experimental: This feature is subject to change.
Note: `engines.node` can be any semver range, with the latest satisfying version being resolved.
[env: FNM_RESOLVE_ENGINES]
-h, --help -h, --help
Print help (see a summary with '-h') Print help (see a summary with '-h')
``` ```
@ -459,6 +508,13 @@ Options:
[env: FNM_COREPACK_ENABLED] [env: FNM_COREPACK_ENABLED]
--resolve-engines
Resolve `engines.node` field in `package.json` whenever a `.node-version` or `.nvmrc` file is not present.
Experimental: This feature is subject to change.
Note: `engines.node` can be any semver range, with the latest satisfying version being resolved.
[env: FNM_RESOLVE_ENGINES]
-h, --help -h, --help
Print help (see a summary with '-h') Print help (see a summary with '-h')
``` ```
@ -513,6 +569,13 @@ Options:
[env: FNM_COREPACK_ENABLED] [env: FNM_COREPACK_ENABLED]
--resolve-engines
Resolve `engines.node` field in `package.json` whenever a `.node-version` or `.nvmrc` file is not present.
Experimental: This feature is subject to change.
Note: `engines.node` can be any semver range, with the latest satisfying version being resolved.
[env: FNM_RESOLVE_ENGINES]
-h, --help -h, --help
Print help (see a summary with '-h') Print help (see a summary with '-h')
``` ```
@ -569,6 +632,13 @@ Options:
[env: FNM_COREPACK_ENABLED] [env: FNM_COREPACK_ENABLED]
--resolve-engines
Resolve `engines.node` field in `package.json` whenever a `.node-version` or `.nvmrc` file is not present.
Experimental: This feature is subject to change.
Note: `engines.node` can be any semver range, with the latest satisfying version being resolved.
[env: FNM_RESOLVE_ENGINES]
-h, --help -h, --help
Print help (see a summary with '-h') Print help (see a summary with '-h')
``` ```
@ -619,6 +689,13 @@ Options:
[env: FNM_COREPACK_ENABLED] [env: FNM_COREPACK_ENABLED]
--resolve-engines
Resolve `engines.node` field in `package.json` whenever a `.node-version` or `.nvmrc` file is not present.
Experimental: This feature is subject to change.
Note: `engines.node` can be any semver range, with the latest satisfying version being resolved.
[env: FNM_RESOLVE_ENGINES]
-h, --help -h, --help
Print help (see a summary with '-h') Print help (see a summary with '-h')
``` ```
@ -681,6 +758,13 @@ Options:
[env: FNM_COREPACK_ENABLED] [env: FNM_COREPACK_ENABLED]
--resolve-engines
Resolve `engines.node` field in `package.json` whenever a `.node-version` or `.nvmrc` file is not present.
Experimental: This feature is subject to change.
Note: `engines.node` can be any semver range, with the latest satisfying version being resolved.
[env: FNM_RESOLVE_ENGINES]
-h, --help -h, --help
Print help (see a summary with '-h') Print help (see a summary with '-h')
``` ```
@ -737,6 +821,13 @@ Options:
[env: FNM_COREPACK_ENABLED] [env: FNM_COREPACK_ENABLED]
--resolve-engines
Resolve `engines.node` field in `package.json` whenever a `.node-version` or `.nvmrc` file is not present.
Experimental: This feature is subject to change.
Note: `engines.node` can be any semver range, with the latest satisfying version being resolved.
[env: FNM_RESOLVE_ENGINES]
-h, --help -h, --help
Print help (see a summary with '-h') Print help (see a summary with '-h')
``` ```

82
e2e/__snapshots__/basic.test.ts.snap

@ -42,6 +42,28 @@ if [ "$(node --version)" != "v8.11.3" ]; then
fi" fi"
`; `;
exports[`Bash package.json engines.node with semver range: Bash 1`] = `
"set -e
eval "$(fnm env --resolve-engines)"
fnm install
fnm use
if [ "$(node --version)" != "v6.17.0" ]; then
echo "Expected node version to be v6.17.0. Got $(node --version)"
exit 1
fi"
`;
exports[`Bash package.json engines.node: Bash 1`] = `
"set -e
eval "$(fnm env --resolve-engines)"
fnm install
fnm use
if [ "$(node --version)" != "v8.11.3" ]; then
echo "Expected node version to be v8.11.3. Got $(node --version)"
exit 1
fi"
`;
exports[`Bash resolves partial semver: Bash 1`] = ` exports[`Bash resolves partial semver: Bash 1`] = `
"set -e "set -e
eval "$(fnm env)" eval "$(fnm env)"
@ -118,6 +140,28 @@ if test "$____test____" != "v8.11.3"
end" end"
`; `;
exports[`Fish package.json engines.node with semver range: Fish 1`] = `
"fnm env --resolve-engines | source
fnm install
fnm use
set ____test____ (node --version)
if test "$____test____" != "v6.17.0"
echo "Expected node version to be v6.17.0. Got $____test____"
exit 1
end"
`;
exports[`Fish package.json engines.node: Fish 1`] = `
"fnm env --resolve-engines | source
fnm install
fnm use
set ____test____ (node --version)
if test "$____test____" != "v8.11.3"
echo "Expected node version to be v8.11.3. Got $____test____"
exit 1
end"
`;
exports[`Fish resolves partial semver: Fish 1`] = ` exports[`Fish resolves partial semver: Fish 1`] = `
"fnm env | source "fnm env | source
fnm install 6 fnm install 6
@ -182,6 +226,22 @@ fnm use v8.11.3
if ( "$(node --version)" -ne "v8.11.3" ) { echo "Expected node version to be v8.11.3. Got $(node --version)"; exit 1 }" if ( "$(node --version)" -ne "v8.11.3" ) { echo "Expected node version to be v8.11.3. Got $(node --version)"; exit 1 }"
`; `;
exports[`PowerShell package.json engines.node with semver range: PowerShell 1`] = `
"$ErrorActionPreference = "Stop"
fnm env --resolve-engines | Out-String | Invoke-Expression
fnm install
fnm use
if ( "$(node --version)" -ne "v6.17.0" ) { echo "Expected node version to be v6.17.0. Got $(node --version)"; exit 1 }"
`;
exports[`PowerShell package.json engines.node: PowerShell 1`] = `
"$ErrorActionPreference = "Stop"
fnm env --resolve-engines | Out-String | Invoke-Expression
fnm install
fnm use
if ( "$(node --version)" -ne "v8.11.3" ) { echo "Expected node version to be v8.11.3. Got $(node --version)"; exit 1 }"
`;
exports[`PowerShell resolves partial semver: PowerShell 1`] = ` exports[`PowerShell resolves partial semver: PowerShell 1`] = `
"$ErrorActionPreference = "Stop" "$ErrorActionPreference = "Stop"
fnm env | Out-String | Invoke-Expression fnm env | Out-String | Invoke-Expression
@ -249,6 +309,28 @@ if [ "$(node --version)" != "v8.11.3" ]; then
fi" fi"
`; `;
exports[`Zsh package.json engines.node with semver range: Zsh 1`] = `
"set -e
eval "$(fnm env --resolve-engines)"
fnm install
fnm use
if [ "$(node --version)" != "v6.17.0" ]; then
echo "Expected node version to be v6.17.0. Got $(node --version)"
exit 1
fi"
`;
exports[`Zsh package.json engines.node: Zsh 1`] = `
"set -e
eval "$(fnm env --resolve-engines)"
fnm install
fnm use
if [ "$(node --version)" != "v8.11.3" ]; then
echo "Expected node version to be v8.11.3. Got $(node --version)"
exit 1
fi"
`;
exports[`Zsh resolves partial semver: Zsh 1`] = ` exports[`Zsh resolves partial semver: Zsh 1`] = `
"set -e "set -e
eval "$(fnm env)" eval "$(fnm env)"

28
e2e/basic.test.ts

@ -40,6 +40,34 @@ for (const shell of [Bash, Zsh, Fish, PowerShell, WinCmd]) {
.execute(shell) .execute(shell)
}) })
test(`package.json engines.node`, async () => {
await writeFile(
join(testCwd(), "package.json"),
JSON.stringify({ engines: { node: "8.11.3" } })
)
await script(shell)
.then(shell.env({ resolveEngines: true }))
.then(shell.call("fnm", ["install"]))
.then(shell.call("fnm", ["use"]))
.then(testNodeVersion(shell, "v8.11.3"))
.takeSnapshot(shell)
.execute(shell)
})
test(`package.json engines.node with semver range`, async () => {
await writeFile(
join(testCwd(), "package.json"),
JSON.stringify({ engines: { node: "^6 < 6.17.1" } })
)
await script(shell)
.then(shell.env({ resolveEngines: true }))
.then(shell.call("fnm", ["install"]))
.then(shell.call("fnm", ["use"]))
.then(testNodeVersion(shell, "v6.17.0"))
.takeSnapshot(shell)
.execute(shell)
})
test(`use on cd`, async () => { test(`use on cd`, async () => {
await mkdir(join(testCwd(), "subdir"), { recursive: true }) await mkdir(join(testCwd(), "subdir"), { recursive: true })
await writeFile(join(testCwd(), "subdir", ".node-version"), "v12.22.12") await writeFile(join(testCwd(), "subdir", ".node-version"), "v12.22.12")

1
e2e/env.test.ts

@ -26,6 +26,7 @@ for (const shell of [Bash, Zsh, Fish, PowerShell, WinCmd]) {
FNM_LOGLEVEL: "info", FNM_LOGLEVEL: "info",
FNM_MULTISHELL_PATH: expect.any(String), FNM_MULTISHELL_PATH: expect.any(String),
FNM_NODE_DIST_MIRROR: expect.any(String), FNM_NODE_DIST_MIRROR: expect.any(String),
FNM_RESOLVE_ENGINES: "false",
FNM_COREPACK_ENABLED: "false", FNM_COREPACK_ENABLED: "false",
FNM_VERSION_FILE_STRATEGY: "local", FNM_VERSION_FILE_STRATEGY: "local",
}) })

2
e2e/shellcode/shells.ts

@ -61,7 +61,7 @@ export const PowerShell = {
...define<Shell>({ ...define<Shell>({
binaryName: () => "pwsh", binaryName: () => "pwsh",
forceFile: ".ps1", forceFile: ".ps1",
currentlySupported: () => true, currentlySupported: () => process.platform === "win32",
name: () => "PowerShell", name: () => "PowerShell",
launchArgs: () => ["-NoProfile"], launchArgs: () => ["-NoProfile"],
escapeText: (x) => x, escapeText: (x) => x,

4
e2e/shellcode/shells/cmdEnv.ts

@ -4,16 +4,18 @@ type EnvConfig = {
useOnCd: boolean useOnCd: boolean
logLevel: string logLevel: string
corepackEnabled: boolean corepackEnabled: boolean
resolveEngines: boolean
} }
export type HasEnv = { env(cfg: Partial<EnvConfig>): ScriptLine } export type HasEnv = { env(cfg: Partial<EnvConfig>): ScriptLine }
function stringify(envConfig: Partial<EnvConfig> = {}) { function stringify(envConfig: Partial<EnvConfig> = {}) {
const { useOnCd, logLevel, corepackEnabled } = envConfig const { useOnCd, logLevel, corepackEnabled, resolveEngines } = envConfig
return [ return [
`fnm env`, `fnm env`,
useOnCd && "--use-on-cd", useOnCd && "--use-on-cd",
logLevel && `--log-level=${logLevel}`, logLevel && `--log-level=${logLevel}`,
corepackEnabled && "--corepack-enabled", corepackEnabled && "--corepack-enabled",
resolveEngines && `--resolve-engines`,
] ]
.filter(Boolean) .filter(Boolean)
.join(" ") .join(" ")

1
src/commands/env.rs

@ -94,6 +94,7 @@ impl Command for Env {
"FNM_COREPACK_ENABLED", "FNM_COREPACK_ENABLED",
config.corepack_enabled().to_string(), config.corepack_enabled().to_string(),
), ),
("FNM_RESOLVE_ENGINES", config.resolve_engines().to_string()),
("FNM_ARCH", config.arch.to_string()), ("FNM_ARCH", config.arch.to_string()),
]); ]);

17
src/config.rs

@ -75,6 +75,18 @@ pub struct FnmConfig {
hide_env_values = true hide_env_values = true
)] )]
corepack_enabled: bool, corepack_enabled: bool,
/// Resolve `engines.node` field in `package.json` whenever a `.node-version` or `.nvmrc` file is not present.
/// Experimental: This feature is subject to change.
/// Note: `engines.node` can be any semver range, with the latest satisfying version being resolved.
#[clap(
long,
env = "FNM_RESOLVE_ENGINES",
global = true,
hide_env_values = true,
verbatim_doc_comment
)]
resolve_engines: bool,
} }
impl Default for FnmConfig { impl Default for FnmConfig {
@ -87,6 +99,7 @@ impl Default for FnmConfig {
arch: Arch::default(), arch: Arch::default(),
version_file_strategy: VersionFileStrategy::default(), version_file_strategy: VersionFileStrategy::default(),
corepack_enabled: false, corepack_enabled: false,
resolve_engines: false,
} }
} }
} }
@ -100,6 +113,10 @@ impl FnmConfig {
self.corepack_enabled self.corepack_enabled
} }
pub fn resolve_engines(&self) -> bool {
self.resolve_engines
}
pub fn multishell_path(&self) -> Option<&std::path::Path> { pub fn multishell_path(&self) -> Option<&std::path::Path> {
match &self.multishell_path { match &self.multishell_path {
None => None, None => None,

1
src/main.rs

@ -20,6 +20,7 @@ mod fs;
mod http; mod http;
mod installed_versions; mod installed_versions;
mod lts; mod lts;
mod package_json;
mod path_ext; mod path_ext;
mod remote_node_index; mod remote_node_index;
mod shell; mod shell;

19
src/package_json.rs

@ -0,0 +1,19 @@
use serde::Deserialize;
#[derive(Debug, Deserialize, Default)]
struct EnginesField {
node: Option<node_semver::Range>,
}
#[derive(Debug, Deserialize, Default)]
pub struct PackageJson {
engines: Option<EnginesField>,
}
impl PackageJson {
pub fn node_range(&self) -> Option<&node_semver::Range> {
self.engines
.as_ref()
.and_then(|engines| engines.node.as_ref())
}
}

3
src/user_version.rs

@ -5,6 +5,7 @@ use std::str::FromStr;
pub enum UserVersion { pub enum UserVersion {
OnlyMajor(u64), OnlyMajor(u64),
MajorMinor(u64, u64), MajorMinor(u64, u64),
SemverRange(node_semver::Range),
Full(Version), Full(Version),
} }
@ -41,6 +42,7 @@ impl UserVersion {
} }
} }
} }
(Self::SemverRange(range), Version::Semver(semver)) => semver.satisfies(range),
(_, Version::Bypassed | Version::Lts(_) | Version::Alias(_) | Version::Latest) => false, (_, Version::Bypassed | Version::Lts(_) | Version::Alias(_) | Version::Latest) => false,
(Self::OnlyMajor(major), Version::Semver(other)) => *major == other.major, (Self::OnlyMajor(major), Version::Semver(other)) => *major == other.major,
(Self::MajorMinor(major, minor), Version::Semver(other)) => { (Self::MajorMinor(major, minor), Version::Semver(other)) => {
@ -59,6 +61,7 @@ impl std::fmt::Display for UserVersion {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {
Self::Full(x) => x.fmt(f), Self::Full(x) => x.fmt(f),
Self::SemverRange(x) => x.fmt(f),
Self::OnlyMajor(major) => write!(f, "v{major}.x.x"), Self::OnlyMajor(major) => write!(f, "v{major}.x.x"),
Self::MajorMinor(major, minor) => write!(f, "v{major}.{minor}.x"), Self::MajorMinor(major, minor) => write!(f, "v{major}.{minor}.x"),
} }

2
src/user_version_reader.rs

@ -14,7 +14,7 @@ impl UserVersionReader {
pub fn into_user_version(self, config: &FnmConfig) -> Option<UserVersion> { pub fn into_user_version(self, config: &FnmConfig) -> Option<UserVersion> {
match self { match self {
Self::Direct(uv) => Some(uv), Self::Direct(uv) => Some(uv),
Self::Path(pathbuf) if pathbuf.is_file() => get_user_version_for_file(pathbuf), Self::Path(pathbuf) if pathbuf.is_file() => get_user_version_for_file(pathbuf, config),
Self::Path(pathbuf) => get_user_version_for_directory(pathbuf, config), Self::Path(pathbuf) => get_user_version_for_directory(pathbuf, config),
} }
} }

59
src/version_files.rs

@ -1,5 +1,6 @@
use crate::config::FnmConfig; use crate::config::FnmConfig;
use crate::default_version; use crate::default_version;
use crate::package_json::PackageJson;
use crate::user_version::UserVersion; use crate::user_version::UserVersion;
use crate::version_file_strategy::VersionFileStrategy; use crate::version_file_strategy::VersionFileStrategy;
use encoding_rs_io::DecodeReaderBytes; use encoding_rs_io::DecodeReaderBytes;
@ -8,28 +9,30 @@ use std::io::Read;
use std::path::Path; use std::path::Path;
use std::str::FromStr; use std::str::FromStr;
const PATH_PARTS: [&str; 2] = [".nvmrc", ".node-version"]; const PATH_PARTS: [&str; 3] = [".nvmrc", ".node-version", "package.json"];
pub fn get_user_version_for_directory( pub fn get_user_version_for_directory(
path: impl AsRef<Path>, path: impl AsRef<Path>,
config: &FnmConfig, config: &FnmConfig,
) -> Option<UserVersion> { ) -> Option<UserVersion> {
match config.version_file_strategy() { match config.version_file_strategy() {
VersionFileStrategy::Local => get_user_version_for_single_directory(path), VersionFileStrategy::Local => get_user_version_for_single_directory(path, config),
VersionFileStrategy::Recursive => { VersionFileStrategy::Recursive => get_user_version_for_directory_recursive(path, config)
get_user_version_for_directory_recursive(path).or_else(|| { .or_else(|| {
info!("Did not find anything recursively. Falling back to default alias."); info!("Did not find anything recursively. Falling back to default alias.");
default_version::find_default_version(config).map(UserVersion::Full) default_version::find_default_version(config).map(UserVersion::Full)
}) }),
}
} }
} }
fn get_user_version_for_directory_recursive(path: impl AsRef<Path>) -> Option<UserVersion> { fn get_user_version_for_directory_recursive(
path: impl AsRef<Path>,
config: &FnmConfig,
) -> Option<UserVersion> {
let mut current_path = Some(path.as_ref()); let mut current_path = Some(path.as_ref());
while let Some(child_path) = current_path { while let Some(child_path) = current_path {
if let Some(version) = get_user_version_for_single_directory(child_path) { if let Some(version) = get_user_version_for_single_directory(child_path, config) {
return Some(version); return Some(version);
} }
@ -39,7 +42,10 @@ fn get_user_version_for_directory_recursive(path: impl AsRef<Path>) -> Option<Us
None None
} }
pub fn get_user_version_for_single_directory(path: impl AsRef<Path>) -> Option<UserVersion> { fn get_user_version_for_single_directory(
path: impl AsRef<Path>,
config: &FnmConfig,
) -> Option<UserVersion> {
let path = path.as_ref(); let path = path.as_ref();
for path_part in &PATH_PARTS { for path_part in &PATH_PARTS {
@ -49,7 +55,7 @@ pub fn get_user_version_for_single_directory(path: impl AsRef<Path>) -> Option<U
new_path.display(), new_path.display(),
new_path.exists() new_path.exists()
); );
if let Some(version) = get_user_version_for_file(&new_path) { if let Some(version) = get_user_version_for_file(&new_path, config) {
return Some(version); return Some(version);
} }
} }
@ -57,22 +63,43 @@ pub fn get_user_version_for_single_directory(path: impl AsRef<Path>) -> Option<U
None None
} }
pub fn get_user_version_for_file(path: impl AsRef<Path>) -> Option<UserVersion> { pub fn get_user_version_for_file(
path: impl AsRef<Path>,
config: &FnmConfig,
) -> Option<UserVersion> {
let is_pkg_json = match path.as_ref().file_name() {
Some(name) => name == "package.json",
None => false,
};
let file = std::fs::File::open(path).ok()?; let file = std::fs::File::open(path).ok()?;
let version = { let file = {
let mut reader = DecodeReaderBytes::new(file); let mut reader = DecodeReaderBytes::new(file);
let mut version = String::new(); let mut version = String::new();
reader.read_to_string(&mut version).map(|_| version) reader.read_to_string(&mut version).map(|_| version)
}; };
match version { match (file, is_pkg_json, config.resolve_engines()) {
Err(err) => { (_, true, false) => None,
(Err(err), _, _) => {
info!("Can't read file: {}", err); info!("Can't read file: {}", err);
None None
} }
Ok(version) => { (Ok(version), false, _) => {
info!("Found string {:?} in version file", version); info!("Found string {:?} in version file", version);
UserVersion::from_str(version.trim()).ok() UserVersion::from_str(version.trim()).ok()
} }
(Ok(pkg_json), true, true) => {
let pkg_json = serde_json::from_str::<PackageJson>(&pkg_json).ok();
let range: Option<node_semver::Range> =
pkg_json.as_ref().and_then(PackageJson::node_range).cloned();
if let Some(range) = range {
info!("Found package.json with {:?} in engines.node field", range);
Some(UserVersion::SemverRange(range))
} else {
info!("No engines.node range found in package.json");
None
}
}
} }
} }

Loading…
Cancel
Save