feat(linter): implement n/no-path-concat rule (#19502)

this PR adds `n/no-path-concat` rule, passes all [test
cases](https://github.com/eslint-community/eslint-plugin-n/blob/master/tests/lib/rules/no-path-concat.js)
from original rule

issue #493

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Cameron Clark <cameron.clark@hey.com>
This commit is contained in:
authored and GitHub committed 2026-02-19 14:58:35 +00:00
1 parent daad7bc557
commit 2b95537911
5 files changed
+332 -1

No files matched your search

+6
View File
@@ -4274,6 +4274,12 @@ impl RuleRunner for crate::rules::node::no_new_require::NoNewRequire {
const RUN_FUNCTIONS: RuleRunFunctionsImplemented = RuleRunFunctionsImplemented::Run;
}
impl RuleRunner for crate::rules::node::no_path_concat::NoPathConcat {
const NODE_TYPES: Option<&AstTypesBitset> =
Some(&AstTypesBitset::from_types(&[AstType::BinaryExpression, AstType::TemplateLiteral]));
const RUN_FUNCTIONS: RuleRunFunctionsImplemented = RuleRunFunctionsImplemented::Run;
}
impl RuleRunner for crate::rules::node::no_process_env::NoProcessEnv {
const NODE_TYPES: Option<&AstTypesBitset> = Some(&AstTypesBitset::from_types(&[
AstType::ComputedMemberExpression,
+25 -1
View File
@@ -336,6 +336,7 @@ pub use crate::rules::nextjs::no_unwanted_polyfillio::NoUnwantedPolyfillio as Ne
pub use crate::rules::node::global_require::GlobalRequire as NodeGlobalRequire;
pub use crate::rules::node::no_exports_assign::NoExportsAssign as NodeNoExportsAssign;
pub use crate::rules::node::no_new_require::NoNewRequire as NodeNoNewRequire;
pub use crate::rules::node::no_path_concat::NoPathConcat as NodeNoPathConcat;
pub use crate::rules::node::no_process_env::NoProcessEnv as NodeNoProcessEnv;
pub use crate::rules::oxc::approx_constant::ApproxConstant as OxcApproxConstant;
pub use crate::rules::oxc::bad_array_method_on_arguments::BadArrayMethodOnArguments as OxcBadArrayMethodOnArguments;
@@ -1379,6 +1380,7 @@ pub enum RuleEnum {
NodeGlobalRequire(NodeGlobalRequire),
NodeNoExportsAssign(NodeNoExportsAssign),
NodeNoNewRequire(NodeNoNewRequire),
NodeNoPathConcat(NodeNoPathConcat),
NodeNoProcessEnv(NodeNoProcessEnv),
VueDefineEmitsDeclaration(VueDefineEmitsDeclaration),
VueDefinePropsDeclaration(VueDefinePropsDeclaration),
@@ -2152,7 +2154,8 @@ const VITEST_WARN_TODO_ID: usize =
const NODE_GLOBAL_REQUIRE_ID: usize = VITEST_WARN_TODO_ID + 1usize;
const NODE_NO_EXPORTS_ASSIGN_ID: usize = NODE_GLOBAL_REQUIRE_ID + 1usize;
const NODE_NO_NEW_REQUIRE_ID: usize = NODE_NO_EXPORTS_ASSIGN_ID + 1usize;
const NODE_NO_PROCESS_ENV_ID: usize = NODE_NO_NEW_REQUIRE_ID + 1usize;
const NODE_NO_PATH_CONCAT_ID: usize = NODE_NO_NEW_REQUIRE_ID + 1usize;
const NODE_NO_PROCESS_ENV_ID: usize = NODE_NO_PATH_CONCAT_ID + 1usize;
const VUE_DEFINE_EMITS_DECLARATION_ID: usize = NODE_NO_PROCESS_ENV_ID + 1usize;
const VUE_DEFINE_PROPS_DECLARATION_ID: usize = VUE_DEFINE_EMITS_DECLARATION_ID + 1usize;
const VUE_DEFINE_PROPS_DESTRUCTURING_ID: usize = VUE_DEFINE_PROPS_DECLARATION_ID + 1usize;
@@ -2949,6 +2952,7 @@ impl RuleEnum {
Self::NodeGlobalRequire(_) => NODE_GLOBAL_REQUIRE_ID,
Self::NodeNoExportsAssign(_) => NODE_NO_EXPORTS_ASSIGN_ID,
Self::NodeNoNewRequire(_) => NODE_NO_NEW_REQUIRE_ID,
Self::NodeNoPathConcat(_) => NODE_NO_PATH_CONCAT_ID,
Self::NodeNoProcessEnv(_) => NODE_NO_PROCESS_ENV_ID,
Self::VueDefineEmitsDeclaration(_) => VUE_DEFINE_EMITS_DECLARATION_ID,
Self::VueDefinePropsDeclaration(_) => VUE_DEFINE_PROPS_DECLARATION_ID,
@@ -3735,6 +3739,7 @@ impl RuleEnum {
Self::NodeGlobalRequire(_) => NodeGlobalRequire::NAME,
Self::NodeNoExportsAssign(_) => NodeNoExportsAssign::NAME,
Self::NodeNoNewRequire(_) => NodeNoNewRequire::NAME,
Self::NodeNoPathConcat(_) => NodeNoPathConcat::NAME,
Self::NodeNoProcessEnv(_) => NodeNoProcessEnv::NAME,
Self::VueDefineEmitsDeclaration(_) => VueDefineEmitsDeclaration::NAME,
Self::VueDefinePropsDeclaration(_) => VueDefinePropsDeclaration::NAME,
@@ -4565,6 +4570,7 @@ impl RuleEnum {
Self::NodeGlobalRequire(_) => NodeGlobalRequire::CATEGORY,
Self::NodeNoExportsAssign(_) => NodeNoExportsAssign::CATEGORY,
Self::NodeNoNewRequire(_) => NodeNoNewRequire::CATEGORY,
Self::NodeNoPathConcat(_) => NodeNoPathConcat::CATEGORY,
Self::NodeNoProcessEnv(_) => NodeNoProcessEnv::CATEGORY,
Self::VueDefineEmitsDeclaration(_) => VueDefineEmitsDeclaration::CATEGORY,
Self::VueDefinePropsDeclaration(_) => VueDefinePropsDeclaration::CATEGORY,
@@ -5354,6 +5360,7 @@ impl RuleEnum {
Self::NodeGlobalRequire(_) => NodeGlobalRequire::FIX,
Self::NodeNoExportsAssign(_) => NodeNoExportsAssign::FIX,
Self::NodeNoNewRequire(_) => NodeNoNewRequire::FIX,
Self::NodeNoPathConcat(_) => NodeNoPathConcat::FIX,
Self::NodeNoProcessEnv(_) => NodeNoProcessEnv::FIX,
Self::VueDefineEmitsDeclaration(_) => VueDefineEmitsDeclaration::FIX,
Self::VueDefinePropsDeclaration(_) => VueDefinePropsDeclaration::FIX,
@@ -6333,6 +6340,7 @@ impl RuleEnum {
Self::NodeGlobalRequire(_) => NodeGlobalRequire::documentation(),
Self::NodeNoExportsAssign(_) => NodeNoExportsAssign::documentation(),
Self::NodeNoNewRequire(_) => NodeNoNewRequire::documentation(),
Self::NodeNoPathConcat(_) => NodeNoPathConcat::documentation(),
Self::NodeNoProcessEnv(_) => NodeNoProcessEnv::documentation(),
Self::VueDefineEmitsDeclaration(_) => VueDefineEmitsDeclaration::documentation(),
Self::VueDefinePropsDeclaration(_) => VueDefinePropsDeclaration::documentation(),
@@ -8259,6 +8267,8 @@ impl RuleEnum {
.or_else(|| NodeNoExportsAssign::schema(generator)),
Self::NodeNoNewRequire(_) => NodeNoNewRequire::config_schema(generator)
.or_else(|| NodeNoNewRequire::schema(generator)),
Self::NodeNoPathConcat(_) => NodeNoPathConcat::config_schema(generator)
.or_else(|| NodeNoPathConcat::schema(generator)),
Self::NodeNoProcessEnv(_) => NodeNoProcessEnv::config_schema(generator)
.or_else(|| NodeNoProcessEnv::schema(generator)),
Self::VueDefineEmitsDeclaration(_) => {
@@ -8986,6 +8996,7 @@ impl RuleEnum {
Self::NodeGlobalRequire(_) => "node",
Self::NodeNoExportsAssign(_) => "node",
Self::NodeNoNewRequire(_) => "node",
Self::NodeNoPathConcat(_) => "node",
Self::NodeNoProcessEnv(_) => "node",
Self::VueDefineEmitsDeclaration(_) => "vue",
Self::VueDefinePropsDeclaration(_) => "vue",
@@ -11163,6 +11174,9 @@ impl RuleEnum {
Self::NodeNoNewRequire(_) => {
Ok(Self::NodeNoNewRequire(NodeNoNewRequire::from_configuration(value)?))
}
Self::NodeNoPathConcat(_) => {
Ok(Self::NodeNoPathConcat(NodeNoPathConcat::from_configuration(value)?))
}
Self::NodeNoProcessEnv(_) => {
Ok(Self::NodeNoProcessEnv(NodeNoProcessEnv::from_configuration(value)?))
}
@@ -11895,6 +11909,7 @@ impl RuleEnum {
Self::NodeGlobalRequire(rule) => rule.to_configuration(),
Self::NodeNoExportsAssign(rule) => rule.to_configuration(),
Self::NodeNoNewRequire(rule) => rule.to_configuration(),
Self::NodeNoPathConcat(rule) => rule.to_configuration(),
Self::NodeNoProcessEnv(rule) => rule.to_configuration(),
Self::VueDefineEmitsDeclaration(rule) => rule.to_configuration(),
Self::VueDefinePropsDeclaration(rule) => rule.to_configuration(),
@@ -12587,6 +12602,7 @@ impl RuleEnum {
Self::NodeGlobalRequire(rule) => rule.run(node, ctx),
Self::NodeNoExportsAssign(rule) => rule.run(node, ctx),
Self::NodeNoNewRequire(rule) => rule.run(node, ctx),
Self::NodeNoPathConcat(rule) => rule.run(node, ctx),
Self::NodeNoProcessEnv(rule) => rule.run(node, ctx),
Self::VueDefineEmitsDeclaration(rule) => rule.run(node, ctx),
Self::VueDefinePropsDeclaration(rule) => rule.run(node, ctx),
@@ -13279,6 +13295,7 @@ impl RuleEnum {
Self::NodeGlobalRequire(rule) => rule.run_once(ctx),
Self::NodeNoExportsAssign(rule) => rule.run_once(ctx),
Self::NodeNoNewRequire(rule) => rule.run_once(ctx),
Self::NodeNoPathConcat(rule) => rule.run_once(ctx),
Self::NodeNoProcessEnv(rule) => rule.run_once(ctx),
Self::VueDefineEmitsDeclaration(rule) => rule.run_once(ctx),
Self::VueDefinePropsDeclaration(rule) => rule.run_once(ctx),
@@ -14069,6 +14086,7 @@ impl RuleEnum {
Self::NodeGlobalRequire(rule) => rule.run_on_jest_node(jest_node, ctx),
Self::NodeNoExportsAssign(rule) => rule.run_on_jest_node(jest_node, ctx),
Self::NodeNoNewRequire(rule) => rule.run_on_jest_node(jest_node, ctx),
Self::NodeNoPathConcat(rule) => rule.run_on_jest_node(jest_node, ctx),
Self::NodeNoProcessEnv(rule) => rule.run_on_jest_node(jest_node, ctx),
Self::VueDefineEmitsDeclaration(rule) => rule.run_on_jest_node(jest_node, ctx),
Self::VueDefinePropsDeclaration(rule) => rule.run_on_jest_node(jest_node, ctx),
@@ -14761,6 +14779,7 @@ impl RuleEnum {
Self::NodeGlobalRequire(rule) => rule.should_run(ctx),
Self::NodeNoExportsAssign(rule) => rule.should_run(ctx),
Self::NodeNoNewRequire(rule) => rule.should_run(ctx),
Self::NodeNoPathConcat(rule) => rule.should_run(ctx),
Self::NodeNoProcessEnv(rule) => rule.should_run(ctx),
Self::VueDefineEmitsDeclaration(rule) => rule.should_run(ctx),
Self::VueDefinePropsDeclaration(rule) => rule.should_run(ctx),
@@ -15739,6 +15758,7 @@ impl RuleEnum {
Self::NodeGlobalRequire(_) => NodeGlobalRequire::IS_TSGOLINT_RULE,
Self::NodeNoExportsAssign(_) => NodeNoExportsAssign::IS_TSGOLINT_RULE,
Self::NodeNoNewRequire(_) => NodeNoNewRequire::IS_TSGOLINT_RULE,
Self::NodeNoPathConcat(_) => NodeNoPathConcat::IS_TSGOLINT_RULE,
Self::NodeNoProcessEnv(_) => NodeNoProcessEnv::IS_TSGOLINT_RULE,
Self::VueDefineEmitsDeclaration(_) => VueDefineEmitsDeclaration::IS_TSGOLINT_RULE,
Self::VueDefinePropsDeclaration(_) => VueDefinePropsDeclaration::IS_TSGOLINT_RULE,
@@ -16598,6 +16618,7 @@ impl RuleEnum {
Self::NodeGlobalRequire(_) => NodeGlobalRequire::HAS_CONFIG,
Self::NodeNoExportsAssign(_) => NodeNoExportsAssign::HAS_CONFIG,
Self::NodeNoNewRequire(_) => NodeNoNewRequire::HAS_CONFIG,
Self::NodeNoPathConcat(_) => NodeNoPathConcat::HAS_CONFIG,
Self::NodeNoProcessEnv(_) => NodeNoProcessEnv::HAS_CONFIG,
Self::VueDefineEmitsDeclaration(_) => VueDefineEmitsDeclaration::HAS_CONFIG,
Self::VueDefinePropsDeclaration(_) => VueDefinePropsDeclaration::HAS_CONFIG,
@@ -17292,6 +17313,7 @@ impl RuleEnum {
Self::NodeGlobalRequire(rule) => rule.types_info(),
Self::NodeNoExportsAssign(rule) => rule.types_info(),
Self::NodeNoNewRequire(rule) => rule.types_info(),
Self::NodeNoPathConcat(rule) => rule.types_info(),
Self::NodeNoProcessEnv(rule) => rule.types_info(),
Self::VueDefineEmitsDeclaration(rule) => rule.types_info(),
Self::VueDefinePropsDeclaration(rule) => rule.types_info(),
@@ -17984,6 +18006,7 @@ impl RuleEnum {
Self::NodeGlobalRequire(rule) => rule.run_info(),
Self::NodeNoExportsAssign(rule) => rule.run_info(),
Self::NodeNoNewRequire(rule) => rule.run_info(),
Self::NodeNoPathConcat(rule) => rule.run_info(),
Self::NodeNoProcessEnv(rule) => rule.run_info(),
Self::VueDefineEmitsDeclaration(rule) => rule.run_info(),
Self::VueDefinePropsDeclaration(rule) => rule.run_info(),
@@ -18792,6 +18815,7 @@ pub static RULES: std::sync::LazyLock<Vec<RuleEnum>> = std::sync::LazyLock::new(
RuleEnum::NodeGlobalRequire(NodeGlobalRequire::default()),
RuleEnum::NodeNoExportsAssign(NodeNoExportsAssign::default()),
RuleEnum::NodeNoNewRequire(NodeNoNewRequire::default()),
RuleEnum::NodeNoPathConcat(NodeNoPathConcat::default()),
RuleEnum::NodeNoProcessEnv(NodeNoProcessEnv::default()),
RuleEnum::VueDefineEmitsDeclaration(VueDefineEmitsDeclaration::default()),
RuleEnum::VueDefinePropsDeclaration(VueDefinePropsDeclaration::default()),
+1
View File
@@ -715,6 +715,7 @@ pub(crate) mod node {
pub mod global_require;
pub mod no_exports_assign;
pub mod no_new_require;
pub mod no_path_concat;
pub mod no_process_env;
}
@@ -0,0 +1,185 @@
use oxc_ast::{
AstKind,
ast::{Expression, TemplateLiteral},
};
use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
use oxc_semantic::IsGlobalReference;
use oxc_span::{Ident, Span};
use oxc_syntax::operator::BinaryOperator;
use crate::{AstNode, context::LintContext, rule::Rule};
fn no_path_concat_diagnostic(span: Span) -> OxcDiagnostic {
OxcDiagnostic::warn("Use `path.join()` or `path.resolve()` instead of string concatenation")
.with_help("Replace string concatenation of `__dirname` or `__filename` with `path.join()` or `path.resolve()`.")
.with_label(span)
}
#[derive(Debug, Default, Clone)]
pub struct NoPathConcat;
declare_oxc_lint!(
/// ### What it does
///
/// Disallows string concatenation with `__dirname` and `__filename`.
///
/// ### Why is this bad?
///
/// In Node.js, the `__dirname` and `__filename` global variables contain the directory path and the file path of the currently executing script file, respectively.
/// Sometimes, developers try to use these variables to create paths to other files, such as:
///
/// ```js
/// var fullPath = __dirname + "/foo.js";
/// ```
///
/// However, this is error-prone because it doesn't account for different
/// operating systems, which use different path separators. Using `path.join()`
/// or `path.resolve()` is the proper way to create cross-platform file paths.
///
/// ### Examples
///
/// Examples of **incorrect** code for this rule:
/// ```js
/// const fullPath1 = __dirname + "/foo.js";
/// const fullPath2 = __filename + "/foo.js";
/// const fullPath3 = `${__dirname}/foo.js`;
/// const fullPath4 = `${__filename}/foo.js`;
/// ```
///
/// Examples of **correct** code for this rule:
/// ```js
/// const fullPath1 = path.join(__dirname, "foo.js");
/// const fullPath2 = path.join(__filename, "foo.js");
/// const fullPath3 = __dirname + ".js";
/// const fullPath4 = __filename + ".map";
/// const fullPath5 = `${__dirname}_foo.js`;
/// const fullPath6 = `${__filename}.test.js`;
/// ```
NoPathConcat,
node,
restriction
);
impl Rule for NoPathConcat {
fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) {
match node.kind() {
AstKind::BinaryExpression(bin_expr) => {
if bin_expr.operator != BinaryOperator::Addition {
return;
}
if is_dirname_or_filename(&bin_expr.left, ctx)
&& starts_with_path_separator(&bin_expr.right)
{
ctx.diagnostic(no_path_concat_diagnostic(bin_expr.span));
}
}
AstKind::TemplateLiteral(temp_lit) => {
for (i, expr) in temp_lit.expressions.iter().enumerate() {
if is_dirname_or_filename(expr, ctx)
&& template_element_starts_with_path_separator(temp_lit, i + 1)
{
ctx.diagnostic(no_path_concat_diagnostic(temp_lit.span));
}
}
}
_ => {}
}
}
}
fn is_path_sep(expr: &Expression) -> bool {
expr.is_specific_member_access("path", "sep")
}
fn is_path_separator(c: char) -> bool {
c == '/' || c == '\\'
}
fn is_dirname_or_filename(expr: &Expression, ctx: &LintContext) -> bool {
let Expression::Identifier(ident) = expr else {
return false;
};
ident.is_global_reference_name(Ident::new_const("__dirname"), ctx.scoping())
|| ident.is_global_reference_name(Ident::new_const("__filename"), ctx.scoping())
}
fn starts_with_path_separator(expr: &Expression) -> bool {
match expr {
Expression::StringLiteral(s) => s.value.chars().next().is_some_and(is_path_separator),
Expression::TemplateLiteral(temp_lit) => {
template_element_starts_with_path_separator(temp_lit, 0)
}
Expression::BinaryExpression(bin) if bin.operator == BinaryOperator::Addition => {
starts_with_path_separator(&bin.left)
}
Expression::ConditionalExpression(cond) => {
starts_with_path_separator(&cond.consequent)
|| starts_with_path_separator(&cond.alternate)
}
Expression::LogicalExpression(logical) => {
starts_with_path_separator(&logical.left) || starts_with_path_separator(&logical.right)
}
Expression::AssignmentExpression(assign) => starts_with_path_separator(&assign.right),
Expression::SequenceExpression(seq) => {
seq.expressions.last().is_some_and(|last| starts_with_path_separator(last))
}
Expression::ParenthesizedExpression(paren) => starts_with_path_separator(&paren.expression),
_ => is_path_sep(expr),
}
}
fn template_element_starts_with_path_separator(temp_lit: &TemplateLiteral, i: usize) -> bool {
let Some(quasi) = temp_lit.quasis.get(i) else {
return false;
};
if let Some(c) = quasi.value.cooked.as_ref().and_then(|cooked| cooked.chars().next())
&& is_path_separator(c)
{
return true;
}
temp_lit.expressions.get(i).is_some_and(|expr| starts_with_path_separator(expr))
}
#[test]
fn test() {
use crate::tester::Tester;
let pass = vec![
r#"var fullPath = dirname + "foo.js";"#,
r#"var fullPath = __dirname == "foo.js";"#,
"if (fullPath === __dirname) {}",
"if (__dirname === fullPath) {}",
r#"var fullPath = "/foo.js" + __filename;"#,
r#"var fullPath = "/foo.js" + __dirname;"#,
r#"var fullPath = __filename + ".map";"#,
"var fullPath = `${__filename}.map`;",
r#"var fullPath = __filename + (test ? ".js" : ".ts");"#,
r#"var fullPath = __filename + (ext || ".js");"#,
r"var fullPath = `${__dirname}\nfoo.js`;",
];
let fail = vec![
r#"var fullPath = __dirname + "/foo.js";"#,
r#"var fullPath = __filename + "/foo.js";"#,
"var fullPath = `${__dirname}/foo.js`;",
"var fullPath = `${__filename}/foo.js`;",
r#"var path = require("path"); var fullPath = `${__dirname}${path.sep}foo.js`;"#,
r#"var path = require("path"); var fullPath = `${__filename}${path.sep}foo.js`;"#,
r#"var path = require("path"); var fullPath = __dirname + path.sep + `foo.js`;"#,
r#"var fullPath = __dirname + "/" + "foo.js";"#,
r#"var fullPath = __dirname + ("/" + "foo.js");"#,
r#"var fullPath = __dirname + (test ? "/foo.js" : "/bar.js");"#,
r#"var fullPath = __dirname + (extraPath || "/default.js");"#,
r#"var fullPath = __dirname + "\\foo.js";"#,
r#"var fullPath = __dirname + "\\${path.sep}foo.js";"#,
r#"var fullPath = __filename + "\\${path.sep}foo.js";"#,
r"var fullPath = `${__dirname}\\${path.sep}foo.js`;",
r"var fullPath = `${__filename}\\${path.sep}foo.js`;",
];
Tester::new(NoPathConcat::NAME, NoPathConcat::PLUGIN, pass, fail).test_and_snapshot();
}
@@ -0,0 +1,115 @@
---
source: crates/oxc_linter/src/tester.rs
---
⚠ eslint-plugin-node(no-path-concat): Use `path.join()` or `path.resolve()` instead of string concatenation
╭─[no_path_concat.tsx:1:16]
1 │ var fullPath = __dirname + "/foo.js";
· ─────────────────────
╰────
help: Replace string concatenation of `__dirname` or `__filename` with `path.join()` or `path.resolve()`.
⚠ eslint-plugin-node(no-path-concat): Use `path.join()` or `path.resolve()` instead of string concatenation
╭─[no_path_concat.tsx:1:16]
1 │ var fullPath = __filename + "/foo.js";
· ──────────────────────
╰────
help: Replace string concatenation of `__dirname` or `__filename` with `path.join()` or `path.resolve()`.
⚠ eslint-plugin-node(no-path-concat): Use `path.join()` or `path.resolve()` instead of string concatenation
╭─[no_path_concat.tsx:1:16]
1 │ var fullPath = `${__dirname}/foo.js`;
· ─────────────────────
╰────
help: Replace string concatenation of `__dirname` or `__filename` with `path.join()` or `path.resolve()`.
⚠ eslint-plugin-node(no-path-concat): Use `path.join()` or `path.resolve()` instead of string concatenation
╭─[no_path_concat.tsx:1:16]
1 │ var fullPath = `${__filename}/foo.js`;
· ──────────────────────
╰────
help: Replace string concatenation of `__dirname` or `__filename` with `path.join()` or `path.resolve()`.
⚠ eslint-plugin-node(no-path-concat): Use `path.join()` or `path.resolve()` instead of string concatenation
╭─[no_path_concat.tsx:1:44]
1 │ var path = require("path"); var fullPath = `${__dirname}${path.sep}foo.js`;
· ───────────────────────────────
╰────
help: Replace string concatenation of `__dirname` or `__filename` with `path.join()` or `path.resolve()`.
⚠ eslint-plugin-node(no-path-concat): Use `path.join()` or `path.resolve()` instead of string concatenation
╭─[no_path_concat.tsx:1:44]
1 │ var path = require("path"); var fullPath = `${__filename}${path.sep}foo.js`;
· ────────────────────────────────
╰────
help: Replace string concatenation of `__dirname` or `__filename` with `path.join()` or `path.resolve()`.
⚠ eslint-plugin-node(no-path-concat): Use `path.join()` or `path.resolve()` instead of string concatenation
╭─[no_path_concat.tsx:1:44]
1 │ var path = require("path"); var fullPath = __dirname + path.sep + `foo.js`;
· ────────────────────
╰────
help: Replace string concatenation of `__dirname` or `__filename` with `path.join()` or `path.resolve()`.
⚠ eslint-plugin-node(no-path-concat): Use `path.join()` or `path.resolve()` instead of string concatenation
╭─[no_path_concat.tsx:1:16]
1 │ var fullPath = __dirname + "/" + "foo.js";
· ───────────────
╰────
help: Replace string concatenation of `__dirname` or `__filename` with `path.join()` or `path.resolve()`.
⚠ eslint-plugin-node(no-path-concat): Use `path.join()` or `path.resolve()` instead of string concatenation
╭─[no_path_concat.tsx:1:16]
1 │ var fullPath = __dirname + ("/" + "foo.js");
· ────────────────────────────
╰────
help: Replace string concatenation of `__dirname` or `__filename` with `path.join()` or `path.resolve()`.
⚠ eslint-plugin-node(no-path-concat): Use `path.join()` or `path.resolve()` instead of string concatenation
╭─[no_path_concat.tsx:1:16]
1 │ var fullPath = __dirname + (test ? "/foo.js" : "/bar.js");
· ──────────────────────────────────────────
╰────
help: Replace string concatenation of `__dirname` or `__filename` with `path.join()` or `path.resolve()`.
⚠ eslint-plugin-node(no-path-concat): Use `path.join()` or `path.resolve()` instead of string concatenation
╭─[no_path_concat.tsx:1:16]
1 │ var fullPath = __dirname + (extraPath || "/default.js");
· ────────────────────────────────────────
╰────
help: Replace string concatenation of `__dirname` or `__filename` with `path.join()` or `path.resolve()`.
⚠ eslint-plugin-node(no-path-concat): Use `path.join()` or `path.resolve()` instead of string concatenation
╭─[no_path_concat.tsx:1:16]
1 │ var fullPath = __dirname + "\\foo.js";
· ──────────────────────
╰────
help: Replace string concatenation of `__dirname` or `__filename` with `path.join()` or `path.resolve()`.
⚠ eslint-plugin-node(no-path-concat): Use `path.join()` or `path.resolve()` instead of string concatenation
╭─[no_path_concat.tsx:1:16]
1 │ var fullPath = __dirname + "\\${path.sep}foo.js";
· ─────────────────────────────────
╰────
help: Replace string concatenation of `__dirname` or `__filename` with `path.join()` or `path.resolve()`.
⚠ eslint-plugin-node(no-path-concat): Use `path.join()` or `path.resolve()` instead of string concatenation
╭─[no_path_concat.tsx:1:16]
1 │ var fullPath = __filename + "\\${path.sep}foo.js";
· ──────────────────────────────────
╰────
help: Replace string concatenation of `__dirname` or `__filename` with `path.join()` or `path.resolve()`.
⚠ eslint-plugin-node(no-path-concat): Use `path.join()` or `path.resolve()` instead of string concatenation
╭─[no_path_concat.tsx:1:16]
1 │ var fullPath = `${__dirname}\\${path.sep}foo.js`;
· ─────────────────────────────────
╰────
help: Replace string concatenation of `__dirname` or `__filename` with `path.join()` or `path.resolve()`.
⚠ eslint-plugin-node(no-path-concat): Use `path.join()` or `path.resolve()` instead of string concatenation
╭─[no_path_concat.tsx:1:16]
1 │ var fullPath = `${__filename}\\${path.sep}foo.js`;
· ──────────────────────────────────
╰────
help: Replace string concatenation of `__dirname` or `__filename` with `path.join()` or `path.resolve()`.