Quick Take

import { strict as assert } from "assert";
import { fixRowNums } from "js-row-num";

// sets line number to 002 because it's on row number two
    `const foo = "bar";\n console.log(\`0 foo = \${foo}\`)`
  `const foo = "bar";\n console.log(\`002 foo = \${foo}\`)`


It updates the numbers in console.logs so that we can know what's happening on which line:

console.log(`056 SET counter = ${counter}`);
// ^ └--------------------┘
// where what happened

Every single package on our monorepo relies on eslint rule eslint-plugin-row-num which is driven by this package.

Result from real life — a snippet of detergent one test dev build's terminal output:

detergent terminal output on dev mode

Notice numbers in front of each logged statement, 073 and 134 and so on. We casually deal with source files spanning thousands of lines.


fixRowNums(str, [opts])

In other words, it's a function which takes two input arguments, second-one being optional (marked by square brackets).

Optional Options Object

options object's key Type of its value Default value Description
padStart Zero, natural number or anything falsy 3 Sets how much digits will be padded
overrideRowNum integer or something falsy null If you have console.log contents already extracted and know the row number, you can pass that row number here. Multiple console.logs on multiple lines won't be recognised, we assume you'll process each console.log one by one.
returnRangesOnly boolean false When enabled, instead of string, program will return result in ranges notation.
triggerKeywords null or array of zero or more strings ["console.log"] After this string, first met chunks of numbers will be replaced with padded row number, unless letter is met first
extractedLogContentsWereGiven Normally we expect whole line to be given, but if you give extracted contents of console.log, activate this flag.

Here it is all in one place:

padStart: 3,
overrideRowNum: null,
returnRangesOnly: false,
triggerKeywords: ["console.log"],
extractedLogContentsWereGiven: false,


Only the digits within console.log string will be replaced.

If the letter (either case) precedes the number, it will not be replaced. We agree that numbers should be in front of the console.log statement:

This row number will be replaced:

console.log("000 This number in front will be replaced");
// ...replaced into:
console.log("001 This number in front will be replaced");

But not this (because letters precede 000):

// will not be replaced:
console.log("This number: 000 will not be replaced because letter precedes it");

The type of quotes doesn't matter: single, double or backticks, as long as opening quote matches the closing quote.

All non-letter characters in front of a digit will not be touched.

Only one lump of digits will be replaced. Second lump onwards will not be touched:

console.log("888 999 This number in front will be replaced");
// ...replaced with:
console.log("001 999 This number in front will be replaced"); // it's first line, so "001"

EOL type does not matter; we support all three types of EOL's: \n, \r and \r\n (see unit tests under group 05.01).

If you don't use console.log, put your function's name in opts.triggerKeywords:

fixRowNums(`a\nb\nc\n log(\`1 something\`)`, { triggerKeywords: ["log"] }),
// => "a\nb\nc\n log(\`004 something\`)"

Above, log() is used and it's on the fourth row and padding is default (three).


If you process each console.log one by one (like we do in eslint-plugin-row-num) and you already know the row number, you can use this program to pad it and perform the replacement.

const fixRowNums = require("js-row-num");
const res = fixRowNums(
console.log('099 something')
overrideRowNum: 5,
// =>
// console.log('005 something')


What are ranges? Composable string amendment instructions. They are arrays containing "from" and "to" string indexes.

For example, a range [1, 5] means an instruction to delete characters which would otherwise fall into String.slice(1, 5).

For example, a range [2, 6, "foo"] means an instruction to replace characters which would otherwise fall into String.slice(2, 6) with string "foo".

That's all there is — we note pieces of string to be deleted or replaced using character indexes and arrays.

Upon request, string-strip-html can also return ranges instead of a final string.

const fixRowNums = require("js-row-num");
const res = fixRowNums(
console.log('099 something')
overrideRowNum: 5,
returnRangesOnly: true,
// =>
// [
// [ 15, 18, "005"]
// ]


Setting opts.triggerKeywords to null will disable all keywords, program will do nothing. In all other cases, where opts.triggerKeywords is an empty array, undefined or boolean false, the default, console.log will kick in and the input will be processed.


Sometimes we have other programs processing the code and console.log contents come in already extracted. We just want this program to extract line numbers and update them. That's when this option comes in.


See it in the monorepo opens in a new tab, on GitHub.


To report bugs or request features or assistance, raise an issue on GitHub opens in a new tab.

Any code contributions welcome! All Pull Requests will be dealt promptly.


MIT opens in a new tab

Copyright © 2010–2021 Roy Revelt and other contributors

Related packages:

📦 js-row-num-cli 2.0.1
Update all row numbers in all console.logs in JS code
📦 edit-package-json 0.5.1
Edit package.json without parsing, as string, to keep the formatting intact
📦 easy-replace 5.0.1
Replace strings with optional lookarounds, but without regexes
📦 str-indexes-of-plus 4.0.1
Like indexOf but returns array and counts per-grapheme
📦 email-all-chars-within-ascii 4.0.1
Scans all characters within a string and checks are they within ASCII range
📦 line-column-mini 2.0.1
Convert string index to line-column position
📦 json-comb 0.6.1
Command line app to manage sets of JSON files