{"record":{"id":"c9a4d7457d440e7a","repo":"oxc-project/oxc","slug":"prefer-string-slice-over-string-method-name","errorCode":null,"errorMessage":"Prefer String#slice() over String#{method_name}()","messagePattern":"Prefer String#slice\\(\\) over String#(.+?)\\(\\)","errorType":"validation","errorClass":"OxcDiagnostic","httpStatus":null,"severity":"warning","filePath":"crates/oxc_linter/src/rules/unicorn/prefer_string_slice.rs","lineNumber":12,"sourceCode":"use oxc_ast::{\n    AstKind,\n    ast::{Argument, Expression, MemberExpression},\n};\nuse oxc_diagnostics::OxcDiagnostic;\nuse oxc_macros::declare_oxc_lint;\nuse oxc_span::Span;\n\nuse crate::{AstNode, context::LintContext, rule::Rule};\n\nfn prefer_string_slice_diagnostic(span: Span, method_name: &str) -> OxcDiagnostic {\n    OxcDiagnostic::warn(format!(\"Prefer String#slice() over String#{method_name}()\"))\n        .with_label(span)\n}\n\n#[derive(Debug, Default, Clone)]\npub struct PreferStringSlice;\n\ndeclare_oxc_lint!(\n    /// ### What it does\n    ///\n    /// Prefer [`String#slice()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/slice) over [`String#substr()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/substr) and [`String#substring()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/substring).\n    ///\n    /// ### Why is this bad?\n    ///\n    /// [`String#substr()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/substr) and [`String#substring()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/substring) are the two lesser known legacy ways to slice a string. It's better to use [`String#slice()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/slice) as it's a more popular option with clearer behavior that has a consistent [`Array` counterpart](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice).\n    ///\n    /// ### Examples\n    ///\n    /// Examples of **incorrect** code for this rule:","sourceCodeStart":1,"sourceCodeEnd":30,"githubUrl":"https://github.com/oxc-project/oxc/blob/e1e7af627c8843ab64044ed466b128fcc21a035b/crates/oxc_linter/src/rules/unicorn/prefer_string_slice.rs#L1-L30","documentation":"This is the oxlint rule `unicorn/prefer-string-slice`. It flags calls to the legacy substring methods `String#substr(start, length)` (deprecated) and `String#substring(a, b)` (with its argument-swapping and negative-clamping quirks) on receivers the rule can resolve to strings, and recommends `String#slice()`, which has consistent index semantics everywhere.","triggerScenarios":"`str.substr(0, 5)`, `str.substring(1, 4)`, or `str.substring(4)` on a receiver recognized as a string (via member-expression checks in the rule's `run`). Computed receivers or optional chains are skipped.","commonSituations":"Porting old JS/jQuery-era code or snippets copied from MDN legacy examples; the real hazard is `substring`'s behavior of swapping arguments when `a > b` and treating negatives as 0, which differs from every other language — reviewers ask for `slice` to remove the footgun. Note `substr`'s second argument is a length, not an end index, so converting requires arithmetic.","solutions":["Rewrite `str.substr(start, len)` as `str.slice(start, start + len)`.","Rewrite `str.substring(a, b)` as `str.slice(a, b)` — but only after confirming `a <= b` and neither argument is negative (otherwise semantics differ).","Run `oxlint --fix` where a fixer applies, and hand-review each conversion for the negative/swap cases.","Disable with `\"unicorn/prefer-string-slice\": \"off\"` if you are maintaining a legacy codebase deliberately matched to old behavior."],"exampleFix":"// before\nconst tail = s.substring(1);\nconst head = s.substr(0, 3);\n\n// after\nconst tail = s.slice(1);\nconst head = s.slice(0, 3);","handlingStrategy":"validation","validationCode":"// Standardize on slice for all substring extraction\nconst head = s.slice(0, 3);\nconst tail = s.slice(-3);\n// CI: npx oxlint --deny-warn unicorn/prefer-string-slice src/","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never write `substring` with possibly-reversed or negative indices; `slice` handles both predictably.","Convert `substr(start, len)` manually — length must become `start + len`.","Grep for `substr(` and `substring(` during dependency upgrades; they are deprecation magnets."],"tags":["oxlint","unicorn","string","legacy-api","slice"],"backgroundTag":"string-slice-over-substr","analyzedSha":"e1e7af627c8843ab64044ed466b128fcc21a035b","analyzedAt":"2026-08-20T07:01:07.079Z","contentChangedAt":"2026-08-20T07:01:07.079Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}