├── .editorconfig ├── .gitignore ├── LICENSE ├── README.md ├── benchmark ├── benchmark.js ├── long.txt └── short.txt ├── gulpfile.js ├── lib └── line-column.js ├── package.json ├── test ├── line-column-test.js └── mocha.opts └── wercker.yml /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.md] 12 | indent_size = 4 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.gitignore.io/api/node 2 | 3 | ### Node ### 4 | # Logs 5 | logs 6 | *.log 7 | npm-debug.log* 8 | 9 | # Runtime data 10 | pids 11 | *.pid 12 | *.seed 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 21 | .grunt 22 | 23 | # node-waf configuration 24 | .lock-wscript 25 | 26 | # Compiled binary addons (http://nodejs.org/api/addons.html) 27 | build/Release 28 | 29 | # Dependency directories 30 | node_modules 31 | jspm_packages 32 | 33 | # Optional npm cache directory 34 | .npm 35 | 36 | # Optional REPL history 37 | .node_repl_history 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 IRIDE Monad 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # line-column 2 | 3 | [![wercker status](https://app.wercker.com/status/791598782525ad7872ecc54e339220dd/s/master "wercker status")](https://app.wercker.com/project/bykey/791598782525ad7872ecc54e339220dd) [![Coverage Status](https://coveralls.io/repos/github/io-monad/line-column/badge.svg?branch=master)](https://coveralls.io/github/io-monad/line-column?branch=master) [![npm version](https://badge.fury.io/js/line-column.svg)](https://badge.fury.io/js/line-column) 4 | 5 | Node module to convert efficiently index to/from line-column in a string. 6 | 7 | ## Install 8 | 9 | npm install line-column 10 | 11 | ## Usage 12 | 13 | ### lineColumn(str, options = {}) 14 | 15 | Returns a `LineColumnFinder` instance for given string `str`. 16 | 17 | #### Options 18 | 19 | | Key | Description | Default | 20 | | ------- | ----------- | ------- | 21 | | `origin` | The origin value of line number and column number | `1` | 22 | 23 | ### lineColumn(str, index) 24 | 25 | This is just a shorthand for `lineColumn(str).fromIndex(index)`. 26 | 27 | ### LineColumnFinder#fromIndex(index) 28 | 29 | Find line and column from index in the string. 30 | 31 | Parameters: 32 | 33 | - `index` - `number` Index in the string. (0-origin) 34 | 35 | Returns: 36 | 37 | - `{ line: x, col: y }` Found line number and column number. 38 | - `null` if the given index is out of range. 39 | 40 | ### LineColumnFinder#toIndex(line, column) 41 | 42 | Find index from line and column in the string. 43 | 44 | Parameters: 45 | 46 | - `line` - `number` Line number in the string. 47 | - `column` - `number` Column number in the string. 48 | 49 | or 50 | 51 | - `{ line: x, col: y }` - `Object` line and column numbers in the string.
A key name `column` can be used instead of `col`. 52 | 53 | or 54 | 55 | - `[ line, col ]` - `Array` line and column numbers in the string. 56 | 57 | Returns: 58 | 59 | - `number` Found index in the string. 60 | - `-1` if the given line or column is out of range. 61 | 62 | ## Example 63 | 64 | ```js 65 | var lineColumn = require("line-column"); 66 | 67 | var testString = [ 68 | "ABCDEFG\n", // line:0, index:0 69 | "HIJKLMNOPQRSTU\n", // line:1, index:8 70 | "VWXYZ\n", // line:2, index:23 71 | "日本語の文字\n", // line:3, index:29 72 | "English words" // line:4, index:36 73 | ].join(""); // length:49 74 | 75 | lineColumn(testString).fromIndex(3) // { line: 1, col: 4 } 76 | lineColumn(testString).fromIndex(33) // { line: 4, col: 5 } 77 | lineColumn(testString).toIndex(1, 4) // 3 78 | lineColumn(testString).toIndex(4, 5) // 33 79 | 80 | // Shorthand of .fromIndex (compatible with find-line-column) 81 | lineColumn(testString, 33) // { line:4, col: 5 } 82 | 83 | // Object or Array is also acceptable 84 | lineColumn(testString).toIndex({ line: 4, col: 5 }) // 33 85 | lineColumn(testString).toIndex({ line: 4, column: 5 }) // 33 86 | lineColumn(testString).toIndex([4, 5]) // 33 87 | 88 | // You can cache it for the same string. It is so efficient. (See benchmark) 89 | var finder = lineColumn(testString); 90 | 91 | finder.fromIndex(33) // { line: 4, column: 5 } 92 | finder.toIndex(4, 5) // 33 93 | 94 | // For 0-origin line and column numbers 95 | var oneOrigin = lineColumn(testString, { origin: 0 }); 96 | 97 | oneOrigin.fromIndex(33) // { line: 3, column: 4 } 98 | oneOrigin.toIndex(3, 4) // 33 99 | ``` 100 | 101 | ## Testing 102 | 103 | npm test 104 | 105 | ## Benchmark 106 | 107 | The popular package [find-line-column](https://www.npmjs.com/package/find-line-column) provides the same "index to line-column" feature. 108 | 109 | Here is some benchmarking on `line-column` vs `find-line-column`. You can run this benchmark by `npm run benchmark`. See [benchmark/](benchmark/) for the source code. 110 | 111 | ``` 112 | long text + line-column (not cached) x 72,989 ops/sec ±0.83% (89 runs sampled) 113 | long text + line-column (cached) x 13,074,242 ops/sec ±0.32% (89 runs sampled) 114 | long text + find-line-column x 33,887 ops/sec ±0.54% (84 runs sampled) 115 | short text + line-column (not cached) x 1,636,766 ops/sec ±0.77% (82 runs sampled) 116 | short text + line-column (cached) x 21,699,686 ops/sec ±1.04% (82 runs sampled) 117 | short text + find-line-column x 382,145 ops/sec ±1.04% (85 runs sampled) 118 | ``` 119 | 120 | As you might have noticed, even not cached version of `line-column` is 2x - 4x faster than `find-line-column`, and cached version of `line-column` is remarkable 50x - 380x faster. 121 | 122 | ## Contributing 123 | 124 | 1. Fork it! 125 | 2. Create your feature branch: `git checkout -b my-new-feature` 126 | 3. Commit your changes: `git commit -am 'Add some feature'` 127 | 4. Push to the branch: `git push origin my-new-feature` 128 | 5. Submit a pull request :D 129 | 130 | ## License 131 | 132 | MIT (See LICENSE) 133 | -------------------------------------------------------------------------------- /benchmark/benchmark.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var Benchmark = require("benchmark"); 4 | var findLineColumn = require("find-line-column"); 5 | var lineColumn = require("../lib/line-column"); 6 | var fs = require("fs"); 7 | 8 | var longText = fs.readFileSync(__dirname + "/long.txt").toString(); 9 | var shortText = fs.readFileSync(__dirname + "/short.txt").toString(); 10 | 11 | var cachedLineColumn1; 12 | var cachedLineColumn2; 13 | 14 | suite 15 | .add("long text + line-column (not cached)", function () { 16 | var index = Math.floor(Math.random() * longText.length); 17 | lineColumn(longText).fromIndex(index); 18 | }) 19 | .add("long text + line-column (cached)", function () { 20 | if (!cachedLineColumn1) cachedLineColumn1 = lineColumn(longText); 21 | var index = Math.floor(Math.random() * longText.length); 22 | cachedLineColumn1.fromIndex(index); 23 | }) 24 | .add("long text + find-line-column", function () { 25 | var index = Math.floor(Math.random() * longText.length); 26 | findLineColumn(longText, index); 27 | }) 28 | .add("short text + line-column (not cached)", function () { 29 | var index = Math.floor(Math.random() * shortText.length); 30 | lineColumn(shortText).fromIndex(index); 31 | }) 32 | .add("short text + line-column (cached)", function () { 33 | if (!cachedLineColumn2) cachedLineColumn2 = lineColumn(shortText); 34 | var index = Math.floor(Math.random() * shortText.length); 35 | cachedLineColumn2.fromIndex(index); 36 | }) 37 | .add("short text + find-line-column", function () { 38 | var index = Math.floor(Math.random() * shortText.length); 39 | findLineColumn(shortText, index); 40 | }) 41 | .on("cycle", function(event) { 42 | console.log(event.target.toString()); 43 | }) 44 | .run({ async: true }); 45 | -------------------------------------------------------------------------------- /benchmark/long.txt: -------------------------------------------------------------------------------- 1 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. 2 | Integer eget nisi nec risus lacinia finibus vel in ligula. 3 | Suspendisse cursus eros nec suscipit tincidunt. 4 | Mauris eget ligula et justo lobortis gravida id sed nisi. 5 | Integer cursus elit non metus dictum iaculis. 6 | Morbi nec magna eget quam eleifend dignissim a id tortor. 7 | Nullam feugiat erat nec placerat blandit. 8 | In at erat viverra, gravida elit vitae, lacinia mauris. 9 | Vivamus quis erat nec ipsum malesuada malesuada ac et magna. 10 | Nullam tincidunt nunc ac pellentesque molestie. 11 | Sed vel lectus eget libero molestie feugiat a a ligula. 12 | Integer id urna at ex egestas suscipit ultricies id quam. 13 | Pellentesque tincidunt tellus non odio hendrerit, ac elementum nunc lacinia. 14 | Duis semper massa sit amet enim feugiat mattis. 15 | Maecenas maximus leo et facilisis bibendum. 16 | Phasellus in velit ut neque facilisis pretium. 17 | Sed id ex a tellus dignissim vulputate. 18 | Quisque vitae urna aliquam enim ultrices pellentesque eget eu purus. 19 | Nullam ultricies tortor et laoreet scelerisque. 20 | Duis sed orci ac sapien placerat dignissim. 21 | Quisque sit amet nibh ac eros tincidunt scelerisque nec vitae ipsum. 22 | Praesent id nisi nec orci malesuada vehicula. 23 | Mauris id nisi placerat, tempor lectus at, suscipit erat. 24 | Phasellus in tortor ac nibh viverra cursus quis non sem. 25 | Donec sit amet lacus at ante egestas tristique. 26 | Etiam nec leo et eros efficitur lobortis ut eu ex. 27 | Sed tincidunt eros sed eros sodales varius. 28 | Duis tristique ex nec massa mollis egestas. 29 | Integer ut felis sed lacus pharetra dapibus in ac nibh. 30 | Morbi id justo ut magna porta egestas a ac augue. 31 | Duis at ligula et urna convallis fringilla sit amet sit amet ipsum. 32 | Integer euismod enim in scelerisque viverra. 33 | Sed maximus tellus a lacus rutrum, molestie viverra dolor imperdiet. 34 | Suspendisse eu velit quis mauris iaculis condimentum. 35 | Pellentesque ultrices eros ac orci sodales malesuada. 36 | Donec viverra erat a dignissim dignissim. 37 | Donec luctus lorem vitae magna consequat accumsan. 38 | Fusce tempor tortor ut malesuada blandit. 39 | Cras id lacus porttitor, consequat nulla id, dapibus purus. 40 | Nunc pellentesque neque eu volutpat euismod. 41 | Quisque sed ipsum non ex viverra ultrices vitae ut neque. 42 | Integer ultricies eros sed ipsum commodo imperdiet. 43 | Ut at lectus pretium arcu ornare placerat eu ac magna. 44 | Nunc in quam dictum, cursus dui eget, ornare sem. 45 | Pellentesque id urna ac eros tincidunt gravida. 46 | Phasellus sollicitudin ante nec sem lacinia fringilla. 47 | Aenean scelerisque elit ac eros imperdiet volutpat. 48 | In vitae magna elementum, eleifend leo eget, pellentesque quam. 49 | Suspendisse condimentum lacus eget libero fringilla, in sagittis nunc rutrum. 50 | Nulla sed turpis vel dolor tristique pharetra. 51 | Aliquam finibus lorem vitae purus tristique, vel placerat nunc feugiat. 52 | Phasellus sit amet magna in arcu convallis ullamcorper. 53 | Aliquam ornare metus quis semper sollicitudin. 54 | Mauris cursus enim nec ex pulvinar, ut commodo est finibus. 55 | Aenean scelerisque nunc non odio gravida, eu posuere risus bibendum. 56 | Quisque venenatis ex vel ante ultrices bibendum. 57 | Pellentesque sit amet purus vel ex finibus vehicula. 58 | Etiam nec purus non elit feugiat consequat in bibendum nisi. 59 | Curabitur ullamcorper nunc fringilla porttitor congue. 60 | Praesent nec diam id mauris euismod aliquam. 61 | Maecenas fringilla tortor nec ipsum ultrices sodales. 62 | Fusce ut odio sed mi convallis semper nec id tortor. 63 | Donec dapibus neque in euismod ultricies. 64 | Duis posuere metus vitae urna egestas pretium. 65 | In eget lacus id velit molestie imperdiet id et felis. 66 | Curabitur efficitur dui eu enim ornare porttitor. 67 | Donec posuere nisi egestas, blandit risus eget, porttitor leo. 68 | Proin condimentum dolor a ex porttitor convallis. 69 | Sed pellentesque ex vitae facilisis blandit. 70 | In semper libero quis tempor sollicitudin. 71 | Suspendisse convallis dui ut nibh tempus scelerisque. 72 | Mauris nec lacus efficitur, tempor enim sit amet, tristique nisl. 73 | Quisque et ante sit amet dui scelerisque suscipit eget vel magna. 74 | Sed suscipit orci nec aliquet fermentum. 75 | Donec volutpat quam nec tincidunt convallis. 76 | In et urna quis nunc gravida consectetur ut quis odio. 77 | Nullam id urna quis elit hendrerit posuere et a nisi. 78 | Aliquam ultricies neque sed libero rutrum dignissim. 79 | Ut convallis quam vel elit tempus volutpat. 80 | Pellentesque porttitor purus et molestie fringilla. 81 | In tempor leo ut ex condimentum cursus. 82 | In eget neque ut eros bibendum fringilla facilisis in est. 83 | Sed euismod augue volutpat, aliquam tellus ac, sagittis sem. 84 | Praesent placerat justo porta dolor euismod, eget tincidunt lectus posuere. 85 | Praesent efficitur eros eget nibh auctor accumsan. 86 | Aenean egestas nulla id felis varius, in vehicula libero posuere. 87 | Pellentesque id tellus quis urna pharetra volutpat vel ut leo. 88 | Fusce sodales diam nec molestie laoreet. 89 | Praesent pretium ex sagittis nisi egestas pulvinar. 90 | Pellentesque ut magna porta, viverra tellus quis, suscipit velit. 91 | Donec vitae augue ac quam fringilla tempor. 92 | Pellentesque sit amet nulla ac leo dictum convallis vel at libero. 93 | Nullam aliquam est vel ligula mattis, sed semper ante aliquam. 94 | Nulla maximus quam sit amet elit hendrerit, vitae viverra turpis scelerisque. 95 | Fusce fringilla tellus eget leo pretium sollicitudin. 96 | Nullam a quam at sapien bibendum mattis nec id nunc. 97 | Sed at quam ut dolor tincidunt malesuada malesuada nec ante. 98 | Fusce aliquam odio sodales sem malesuada, dapibus iaculis purus rutrum. 99 | Proin id ante sit amet augue commodo imperdiet rutrum a odio. 100 | Quisque tempor mi ut ex dignissim vulputate. 101 | Phasellus non urna eget quam aliquet interdum in sit amet orci. 102 | Praesent mattis metus at vestibulum mattis. 103 | Curabitur dictum nisl ut leo volutpat, vel aliquet lacus elementum. 104 | Mauris et nunc sit amet neque semper lobortis ac in nulla. 105 | Suspendisse et mi at magna placerat tristique vel sit amet leo. 106 | Vestibulum vel ligula sed metus tristique laoreet. 107 | Proin quis justo quis metus eleifend pretium et vitae nulla. 108 | Sed interdum nunc sed ex porta, quis semper eros lobortis. 109 | Fusce non metus convallis, euismod est id, eleifend odio. 110 | Phasellus ut tellus placerat, euismod nulla in, lacinia nibh. 111 | Sed pellentesque mi a arcu mollis, vel accumsan massa rutrum. 112 | Etiam consectetur nulla in sollicitudin suscipit. 113 | Mauris et diam ut arcu vulputate aliquet. 114 | Phasellus malesuada libero et fringilla consectetur. 115 | Donec in odio eget velit scelerisque efficitur at non tellus. 116 | Curabitur a nibh mattis, viverra eros vel, condimentum metus. 117 | Sed nec augue ac lorem consectetur bibendum. 118 | Cras in ipsum scelerisque augue vulputate scelerisque id ut neque. 119 | Morbi aliquam mauris porttitor elit consectetur, sit amet varius ex mollis. 120 | Nunc semper metus quis lacus auctor, a ultrices sapien dignissim. 121 | Curabitur sed leo vitae dolor commodo accumsan ac vitae dui. 122 | Cras sed leo id arcu rutrum volutpat id a risus. 123 | Vestibulum ac arcu ornare, tincidunt tortor vel, sagittis neque. 124 | Phasellus lacinia augue at mauris varius, eget viverra lacus ullamcorper. 125 | Praesent feugiat purus et quam pulvinar scelerisque. 126 | Praesent eleifend ipsum ac sapien dignissim interdum. 127 | Etiam eu eros sed nisl luctus finibus. 128 | Morbi nec nunc lacinia, eleifend libero euismod, mollis lacus. 129 | Nam ac nunc at est laoreet bibendum quis eget ex. 130 | Nullam a risus id metus dictum vehicula. 131 | Suspendisse eget tortor eleifend, euismod dui eget, mattis metus. 132 | Morbi vitae velit vel magna dignissim tincidunt ac eget nisl. 133 | Nunc malesuada felis ac cursus volutpat. 134 | Mauris id nisl in mauris tincidunt vehicula eu eu nisl. 135 | Curabitur dapibus tellus eu neque maximus, nec vestibulum tellus blandit. 136 | Vestibulum eleifend quam at sem sagittis, laoreet porttitor massa euismod. 137 | Donec sagittis enim in nibh dapibus consequat. 138 | Vivamus scelerisque lacus commodo massa condimentum, eget tempor quam pretium. 139 | Duis vitae odio nec mi auctor volutpat vel sit amet lorem. 140 | Aliquam ac orci bibendum, posuere metus sit amet, mattis mauris. 141 | Aliquam non turpis vulputate tellus iaculis aliquet quis sit amet orci. 142 | Praesent quis risus non nisl ultrices accumsan id at est. 143 | Integer vitae orci vel lectus accumsan placerat. 144 | Fusce convallis arcu sit amet velit cursus, eu elementum nisl iaculis. 145 | Donec sit amet mi sit amet erat tristique dictum. 146 | In dapibus felis non fermentum dapibus. 147 | Aliquam et purus egestas, cursus turpis at, convallis libero. 148 | Ut in arcu ac elit iaculis ultricies vel vel augue. 149 | Vivamus ac libero id velit interdum vehicula non sit amet leo. 150 | Nunc mattis justo vel mollis pulvinar. 151 | Duis in diam eu nibh sollicitudin pharetra a vitae ante. 152 | Cras tempor est eget accumsan iaculis. 153 | Curabitur fringilla dolor et mauris laoreet, in bibendum erat tempus. 154 | Praesent nec diam iaculis odio consequat tempus. 155 | Integer sit amet diam non diam convallis interdum. 156 | Fusce vitae nunc maximus, malesuada orci nec, vestibulum velit. 157 | Nulla auctor est ut ex convallis, nec mattis orci lobortis. 158 | Suspendisse semper metus ac ex pellentesque, et ullamcorper augue lacinia. 159 | Quisque vel libero ornare, ornare augue faucibus, cursus sem. 160 | Cras gravida metus at ipsum laoreet pulvinar laoreet quis ante. 161 | Proin fringilla libero nec diam pharetra interdum. 162 | Suspendisse feugiat erat nec facilisis vulputate. 163 | Nunc cursus est eu purus gravida iaculis. 164 | Integer ut augue gravida elit sollicitudin hendrerit ac non ex. 165 | Donec consequat massa sed maximus tincidunt. 166 | Duis auctor elit ac turpis aliquam, eu finibus libero vestibulum. 167 | Fusce tristique diam et risus elementum, ut sagittis tortor mattis. 168 | In aliquam enim in malesuada iaculis. 169 | Ut et lacus et justo sagittis elementum. 170 | Nunc consectetur sem eget sapien fermentum viverra. 171 | Phasellus id libero at nibh ultricies elementum. 172 | Vestibulum at dui eu neque imperdiet laoreet ac in felis. 173 | Nullam dictum velit a iaculis aliquam. 174 | Duis ac risus non dui placerat lobortis. 175 | Sed sit amet urna et justo ultricies pellentesque sit amet tempus mi. 176 | Nam ac urna id orci sollicitudin eleifend eu in massa. 177 | Quisque condimentum turpis quis arcu dignissim, vel pretium nulla blandit. 178 | Integer lacinia erat a arcu lobortis dictum. 179 | Maecenas non nibh a ante porta euismod et ac urna. 180 | Nam venenatis ligula vitae justo efficitur malesuada. 181 | Pellentesque ut sem vitae sem egestas iaculis non sit amet neque. 182 | Proin at arcu eu mi ullamcorper maximus. 183 | Pellentesque ultrices risus sed diam viverra, quis ornare elit elementum. 184 | Donec commodo ex sed velit venenatis, vel efficitur turpis euismod. 185 | Ut sed lorem hendrerit, venenatis ex nec, congue massa. 186 | Duis efficitur lectus nec facilisis feugiat. 187 | Duis et dui id justo volutpat efficitur nec cursus tortor. 188 | Etiam ac augue vel metus rutrum posuere quis vel ipsum. 189 | Maecenas vitae urna sed sem elementum malesuada suscipit at augue. 190 | Morbi ultricies sapien quis dolor ultrices, ut semper dui suscipit. 191 | Suspendisse quis mi at erat sollicitudin luctus quis eu quam. 192 | Sed porta nulla sed tortor egestas blandit. 193 | Curabitur non est eget sapien venenatis vulputate quis at ipsum. 194 | Proin volutpat orci et nibh mattis, ut luctus metus pretium. 195 | Donec ut metus porttitor, aliquam quam ac, euismod lacus. 196 | Praesent nec felis rutrum mauris tempor pretium ut et ex. 197 | Nullam fringilla nulla molestie maximus lacinia. 198 | Sed vel nisi aliquet quam sagittis faucibus sit amet non massa. 199 | Morbi aliquam diam nec tincidunt posuere. 200 | Suspendisse id urna in mauris viverra euismod. 201 | Donec interdum tortor vitae dolor faucibus hendrerit. 202 | Curabitur fermentum mauris at euismod hendrerit. 203 | Vestibulum ac augue rhoncus, facilisis felis id, imperdiet erat. 204 | Sed et diam facilisis, maximus lacus id, vulputate lorem. 205 | Vivamus eget dui ornare, facilisis dui et, varius erat. 206 | Pellentesque ultricies elit vel gravida convallis. 207 | Duis dignissim nulla id varius semper. 208 | Pellentesque a felis efficitur, euismod lorem a, consectetur elit. 209 | Curabitur eleifend nibh sed mi scelerisque, quis condimentum turpis scelerisque. 210 | Integer eget sapien viverra, ullamcorper nibh sit amet, placerat orci. 211 | Nulla consectetur mi sit amet massa commodo, ultrices rutrum nulla euismod. 212 | Mauris eu nulla sollicitudin, dapibus est et, mattis ipsum. 213 | Proin ultricies nisl quis arcu rhoncus, sit amet tempor ligula tincidunt. 214 | Mauris bibendum purus non pretium tincidunt. 215 | Nunc varius nunc non ultrices auctor. 216 | Quisque gravida libero at est ultrices, a interdum eros consequat. 217 | Curabitur dapibus libero id elit aliquet, eu feugiat massa gravida. 218 | Curabitur in diam tincidunt arcu vulputate bibendum. 219 | Duis scelerisque sem pellentesque, congue diam in, efficitur diam. 220 | Fusce et elit finibus sem ultricies aliquam vitae vel massa. 221 | Suspendisse lobortis neque eget mauris volutpat sollicitudin. 222 | Nullam lobortis enim non erat sodales, ac aliquet ligula varius. 223 | Aenean ullamcorper diam vel enim feugiat bibendum sed in arcu. 224 | Aliquam at leo tristique, pharetra massa et, porttitor augue. 225 | Proin pellentesque metus in felis feugiat maximus. 226 | Mauris et ante quis lectus efficitur mattis. 227 | Donec sed ligula tempus, rutrum turpis non, pellentesque nunc. 228 | Fusce vitae nibh accumsan libero tristique egestas eu eget lorem. 229 | Nunc sit amet justo eget ligula suscipit porta. 230 | In eget magna ultricies, lobortis arcu id, pharetra magna. 231 | Donec id turpis ut lorem tristique vestibulum. 232 | Cras tristique nibh et dapibus molestie. 233 | Nulla nec lectus at orci cursus aliquet ut nec ex. 234 | Aenean tincidunt dolor at nisi efficitur, in tincidunt dui bibendum. 235 | Donec vestibulum nisi at laoreet malesuada. 236 | Duis aliquet odio a porta semper. 237 | Ut id odio vitae dolor dapibus ornare. 238 | Praesent mattis nulla vestibulum metus tincidunt, at porta enim condimentum. 239 | Nam sed orci at turpis suscipit consequat ac in leo. 240 | Aenean ut justo id ligula gravida luctus nec vel elit. 241 | Pellentesque ornare ante in suscipit euismod. 242 | Cras ut nunc vitae eros facilisis consequat. 243 | Suspendisse pretium dui id lectus aliquet vehicula. 244 | Donec posuere mauris vitae quam tempor molestie. 245 | Donec dapibus magna eget lectus posuere pulvinar. 246 | Morbi sed ante faucibus, molestie risus a, aliquet magna. 247 | Fusce quis purus tristique purus venenatis consectetur. 248 | Suspendisse rutrum nisl ornare nisi pharetra gravida. 249 | Fusce rhoncus ante vestibulum, porta arcu sit amet, hendrerit mauris. 250 | Aenean malesuada dolor a nunc sagittis, quis commodo nunc dapibus. 251 | Fusce nec augue tristique, efficitur nibh vitae, bibendum ligula. 252 | Fusce aliquam turpis sed tincidunt venenatis. 253 | Sed nec nisi eget justo scelerisque feugiat. 254 | Ut lacinia turpis sit amet tristique vehicula. 255 | Etiam et arcu vel risus pulvinar faucibus. 256 | Sed convallis felis non lectus euismod, sed feugiat ligula dapibus. 257 | Suspendisse rutrum velit consectetur, tempor dolor in, congue eros. 258 | Duis vel mi maximus elit faucibus pretium. 259 | Curabitur eu erat viverra, tristique elit quis, auctor neque. 260 | Praesent quis ipsum condimentum, pellentesque tellus nec, venenatis tellus. 261 | Vestibulum facilisis ex vel nunc placerat, vitae pulvinar libero viverra. 262 | Aliquam suscipit neque at eros tincidunt, aliquam elementum ligula viverra. 263 | Mauris consequat quam elementum metus euismod, sit amet interdum felis elementum. 264 | Etiam posuere lectus et nisi sagittis, id rutrum metus porttitor. 265 | Vivamus malesuada elit vitae orci sodales, ac lobortis elit suscipit. 266 | Mauris blandit justo sed est convallis, vel dapibus felis pellentesque. 267 | Sed dapibus enim eget elit scelerisque, eget accumsan augue consectetur. 268 | In accumsan magna vitae erat egestas, ut eleifend enim efficitur. 269 | Morbi at nibh non leo suscipit dapibus. 270 | Vestibulum et metus nec quam tincidunt rutrum non quis lacus. 271 | In vel nisi fermentum nisi rhoncus rhoncus a sit amet massa. 272 | Nullam cursus risus in orci lacinia accumsan. 273 | Quisque fermentum felis vel justo vehicula, quis tristique dolor tristique. 274 | Etiam interdum neque imperdiet eros ultricies, id bibendum lacus rutrum. 275 | Vivamus sit amet ligula ac dolor tincidunt vehicula. 276 | Proin sit amet metus tincidunt, viverra velit sit amet, scelerisque enim. 277 | Duis tristique augue et ipsum sagittis lacinia. 278 | Donec sagittis justo quis odio lobortis, quis consequat sem malesuada. 279 | Fusce sed mi non arcu accumsan fringilla ut nec mauris. 280 | Proin a elit dictum, cursus diam vitae, semper turpis. 281 | Nulla ultricies sapien eu odio malesuada, in pharetra tellus pharetra. 282 | Donec quis ligula in dolor posuere fringilla. 283 | Nam aliquam nunc in quam eleifend auctor. 284 | Cras ac tellus nec augue auctor tristique et nec turpis. 285 | Ut sit amet sapien nec erat congue ornare non ut massa. 286 | Mauris pulvinar nisl ut ligula interdum sodales. 287 | Phasellus semper lacus in sem pretium mattis. 288 | Maecenas quis dui sit amet mi malesuada euismod at id tellus. 289 | Cras blandit arcu ut felis sollicitudin accumsan. 290 | Suspendisse efficitur arcu id ullamcorper sollicitudin. 291 | Vestibulum at ex eu metus imperdiet posuere. 292 | Sed tristique erat eget ligula varius, eget pellentesque leo viverra. 293 | Pellentesque nec dolor vulputate, pretium felis vel, bibendum nisl. 294 | Morbi at nisi luctus, laoreet orci nec, pulvinar metus. 295 | Donec lobortis diam at urna commodo, consequat maximus nisl fringilla. 296 | Ut mattis mi id lorem pretium aliquam. 297 | Ut vitae mauris eget est mattis ultricies sed ut velit. 298 | Nulla tempor arcu a fermentum pharetra. 299 | Aliquam cursus urna nec purus eleifend, at ullamcorper eros egestas. 300 | Nulla lobortis purus eget dolor gravida ornare. 301 | Maecenas egestas arcu ut dolor sodales, vel tincidunt enim suscipit. 302 | Suspendisse id purus eu odio feugiat mollis. 303 | Aliquam ut ante interdum, dignissim nulla condimentum, eleifend nisl. 304 | Morbi commodo sapien eu dapibus sodales. 305 | Nulla vitae lectus ac est lobortis sollicitudin. 306 | Nullam varius risus quis tortor fermentum aliquet. 307 | Aenean eleifend elit ac varius dictum. 308 | Nullam non sapien volutpat, venenatis quam et, bibendum magna. 309 | Ut dapibus felis non fringilla bibendum. 310 | Nam tempor lorem ut tempus convallis. 311 | Phasellus vestibulum tortor sed tellus condimentum, ut lobortis turpis dapibus. 312 | Nunc vel augue eleifend, fringilla nulla a, lobortis justo. 313 | Nunc malesuada enim quis dui venenatis scelerisque. 314 | Sed quis sem id ante cursus malesuada eu dignissim risus. 315 | Cras ac arcu ac nulla molestie varius. 316 | Curabitur vestibulum orci nec suscipit ornare. 317 | Proin in sapien in lorem porttitor condimentum id ac risus. 318 | Praesent vehicula ipsum id nisi aliquet, vel consequat urna vehicula. 319 | Nulla a nisi ac elit scelerisque placerat. 320 | Maecenas suscipit massa sit amet metus aliquet, et suscipit ante efficitur. 321 | Nam ut ipsum at diam auctor lacinia. 322 | Vestibulum non nibh id ipsum placerat ornare. 323 | Etiam consectetur lorem sit amet quam pharetra scelerisque. 324 | Mauris mattis neque sagittis, tristique leo ac, pretium massa. 325 | Nam sit amet augue rutrum, interdum mi et, aliquam leo. 326 | Cras accumsan mauris mattis erat rutrum maximus. 327 | Morbi condimentum ante mattis, lacinia metus et, pellentesque nulla. 328 | Vestibulum suscipit risus et enim sollicitudin, nec suscipit nibh eleifend. 329 | Phasellus congue urna ut neque ornare rutrum. 330 | In non mauris ut ligula elementum sodales molestie a tortor. 331 | Nunc tincidunt elit eget libero blandit pulvinar. 332 | Nunc dictum lorem id varius convallis. 333 | Fusce tristique urna quis fermentum eleifend. 334 | Vestibulum consectetur odio eu eros dictum dictum. 335 | Curabitur aliquam ipsum quis commodo tempor. 336 | Proin fringilla eros pretium, fermentum ligula eget, dapibus metus. 337 | Pellentesque lobortis sem sed velit euismod interdum. 338 | Donec convallis justo id tempor pulvinar. 339 | -------------------------------------------------------------------------------- /benchmark/short.txt: -------------------------------------------------------------------------------- 1 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. 2 | Sed consectetur ante non ipsum congue, eget pellentesque magna euismod. 3 | Maecenas in mi at nisi semper pellentesque. 4 | Donec vel nunc posuere, efficitur felis eu, suscipit sapien. 5 | Quisque ut nulla non dui dignissim tristique. 6 | Maecenas at mi sodales augue tincidunt sagittis ut porttitor ipsum. 7 | Proin venenatis risus sed velit congue molestie eget nec lorem. 8 | Mauris scelerisque odio vel ornare vestibulum. -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var gulp = require("gulp"); 4 | var plumber = require("gulp-plumber"); 5 | var mocha = require("gulp-mocha"); 6 | var istanbul = require("gulp-istanbul"); 7 | var coveralls = require("gulp-coveralls"); 8 | 9 | gulp.task("default", ["coverage"]); 10 | 11 | gulp.task("watch", function () { 12 | gulp.watch(["lib/**", "test/**"], ["test"]); 13 | }); 14 | 15 | gulp.task("test", function () { 16 | return gulp.src("test/**/*.js", { read: false }) 17 | .pipe(mocha()); 18 | }); 19 | 20 | gulp.task("pre-coverage", function () { 21 | return gulp.src("lib/**/*.js") 22 | .pipe(istanbul()) 23 | .pipe(istanbul.hookRequire()); 24 | }); 25 | 26 | gulp.task("coverage", ["pre-coverage"], function (cb) { 27 | var mochaError; 28 | gulp.src("test/**/*.js", { read: false }) 29 | .pipe(plumber()) 30 | .pipe(mocha()) 31 | .on("error", function (err) { mochaError = err }) 32 | .pipe(istanbul.writeReports()) 33 | .on("end", function () { cb(mochaError) }); 34 | }); 35 | 36 | gulp.task("test-ci", ["coverage"], function () { 37 | return gulp.src("coverage/lcov.info") 38 | .pipe(coveralls()); 39 | }); 40 | -------------------------------------------------------------------------------- /lib/line-column.js: -------------------------------------------------------------------------------- 1 | /** 2 | * line-column - Convert efficiently index to/from line-column in a string 3 | * @module lineColumn 4 | * @license MIT 5 | */ 6 | "use strict"; 7 | 8 | var isArray = require("isarray"); 9 | var isObject = require("isobject"); 10 | var slice = Array.prototype.slice; 11 | 12 | module.exports = LineColumnFinder; 13 | 14 | /** 15 | * Finder for index and line-column from given string. 16 | * 17 | * You can call this without `new` operator as it returns an instance anyway. 18 | * 19 | * @class 20 | * @param {string} str - A string to be parsed. 21 | * @param {Object|number} [options] - Options. 22 | * This can be an index in the string for shorthand of `lineColumn(str, index)`. 23 | * @param {number} [options.origin=1] - The origin value of line and column. 24 | */ 25 | function LineColumnFinder(str, options) { 26 | if (!(this instanceof LineColumnFinder)) { 27 | if (typeof options === "number") { 28 | return (new LineColumnFinder(str)).fromIndex(options); 29 | } 30 | return new LineColumnFinder(str, options); 31 | } 32 | 33 | this.str = str || ""; 34 | this.lineToIndex = buildLineToIndex(this.str); 35 | 36 | options = options || {}; 37 | this.origin = typeof options.origin === "undefined" ? 1 : options.origin; 38 | } 39 | 40 | /** 41 | * Find line and column from index in the string. 42 | * 43 | * @param {number} index - Index in the string. (0-origin) 44 | * @return {Object|null} 45 | * Found line number and column number in object `{ line: X, col: Y }`. 46 | * If the given index is out of range, it returns `null`. 47 | */ 48 | LineColumnFinder.prototype.fromIndex = function (index) { 49 | if (index < 0 || index >= this.str.length || isNaN(index)) { 50 | return null; 51 | } 52 | 53 | var line = findLowerIndexInRangeArray(index, this.lineToIndex); 54 | return { 55 | line: line + this.origin, 56 | col: index - this.lineToIndex[line] + this.origin 57 | }; 58 | } 59 | 60 | /** 61 | * Find index from line and column in the string. 62 | * 63 | * @param {number|Object|Array} line - Line number in the string. 64 | * This can be an Object of `{ line: X, col: Y }`, or 65 | * an Array of `[line, col]`. 66 | * @param {number} [column] - Column number in the string. 67 | * This must be omitted or undefined when Object or Array is given 68 | * to the first argument. 69 | * @return {number} 70 | * Found index in the string. (always 0-origin) 71 | * If the given line or column is out of range, it returns `-1`. 72 | */ 73 | LineColumnFinder.prototype.toIndex = function (line, column) { 74 | if (typeof column === "undefined") { 75 | if (isArray(line) && line.length >= 2) { 76 | return this.toIndex(line[0], line[1]); 77 | } 78 | if (isObject(line) && "line" in line && ("col" in line || "column" in line)) { 79 | return this.toIndex(line.line, ("col" in line ? line.col : line.column)); 80 | } 81 | return -1; 82 | } 83 | if (isNaN(line) || isNaN(column)) { 84 | return -1; 85 | } 86 | 87 | line -= this.origin; 88 | column -= this.origin; 89 | 90 | if (line >= 0 && column >= 0 && line < this.lineToIndex.length) { 91 | var lineIndex = this.lineToIndex[line]; 92 | var nextIndex = ( 93 | line === this.lineToIndex.length - 1 94 | ? this.str.length 95 | : this.lineToIndex[line + 1] 96 | ); 97 | 98 | if (column < nextIndex - lineIndex) { 99 | return lineIndex + column; 100 | } 101 | } 102 | return -1; 103 | } 104 | 105 | /** 106 | * Build an array of indexes of each line from a string. 107 | * 108 | * @private 109 | * @param str {string} An input string. 110 | * @return {number[]} Built array of indexes. The key is line number. 111 | */ 112 | function buildLineToIndex(str) { 113 | var lines = str.split("\n"), 114 | lineToIndex = new Array(lines.length), 115 | index = 0; 116 | 117 | for (var i = 0, l = lines.length; i < l; i++) { 118 | lineToIndex[i] = index; 119 | index += lines[i].length + /* "\n".length */ 1; 120 | } 121 | return lineToIndex; 122 | } 123 | 124 | /** 125 | * Find a lower-bound index of a value in a sorted array of ranges. 126 | * 127 | * Assume `arr = [0, 5, 10, 15, 20]` and 128 | * this returns `1` for `value = 7` (5 <= value < 10), 129 | * and returns `3` for `value = 18` (15 <= value < 20). 130 | * 131 | * @private 132 | * @param arr {number[]} An array of values representing ranges. 133 | * @param value {number} A value to be searched. 134 | * @return {number} Found index. If not found `-1`. 135 | */ 136 | function findLowerIndexInRangeArray(value, arr) { 137 | if (value >= arr[arr.length - 1]) { 138 | return arr.length - 1; 139 | } 140 | 141 | var min = 0, max = arr.length - 2, mid; 142 | while (min < max) { 143 | mid = min + ((max - min) >> 1); 144 | 145 | if (value < arr[mid]) { 146 | max = mid - 1; 147 | } else if (value >= arr[mid + 1]) { 148 | min = mid + 1; 149 | } else { // value >= arr[mid] && value < arr[mid + 1] 150 | min = mid; 151 | break; 152 | } 153 | } 154 | return min; 155 | } 156 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "line-column", 3 | "version": "1.0.2", 4 | "description": "Convert efficiently index to/from line-column in a string", 5 | "author": "IRIDE Monad ", 6 | "license": "MIT", 7 | "repository": "io-monad/line-column", 8 | "homepage": "https://github.com/io-monad/line-column", 9 | "bugs": { 10 | "url": "https://github.com/io-monad/line-column/issues" 11 | }, 12 | "keywords": [ 13 | "string", 14 | "index", 15 | "line", 16 | "column", 17 | "linecol", 18 | "position" 19 | ], 20 | "main": "lib/line-column.js", 21 | "files": [ 22 | "lib" 23 | ], 24 | "scripts": { 25 | "test": "gulp test", 26 | "test-ci": "gulp test-ci", 27 | "watch": "gulp watch", 28 | "benchmark": "node benchmark/benchmark.js" 29 | }, 30 | "devDependencies": { 31 | "benchmark": "^2.1.0", 32 | "find-line-column": "^0.5.2", 33 | "gulp": "^3.9.1", 34 | "gulp-coveralls": "^0.1.4", 35 | "gulp-istanbul": "^1.0.0", 36 | "gulp-mocha": "^2.2.0", 37 | "gulp-plumber": "^1.1.0", 38 | "intelli-espower-loader": "^1.0.1", 39 | "istanbul": "^0.4.2", 40 | "mocha": "^2.4.5", 41 | "power-assert": "^1.3.1" 42 | }, 43 | "dependencies": { 44 | "isarray": "^1.0.0", 45 | "isobject": "^2.0.0" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /test/line-column-test.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var LineColumnFinder = require("../lib/line-column"); 4 | var assert = require("power-assert"); 5 | 6 | var testString = [ 7 | "ABCDEFG\n", // line:0, index:0 8 | "HIJKLMNOPQRSTU\n", // line:1, index:8 9 | "VWXYZ\n", // line:2, index:23 10 | "日本語の文字\n", // line:3, index:29 11 | "English words" // line:4, index:36 12 | ].join(""); // length:49 13 | 14 | describe("LineColumnFinder", function () { 15 | 16 | describe("#constructor", function () { 17 | it("can be called with new operator", function () { 18 | assert(new LineColumnFinder("TEST") instanceof LineColumnFinder); 19 | }); 20 | it("can be called without new operator", function () { 21 | assert(LineColumnFinder("TEST") instanceof LineColumnFinder); 22 | }); 23 | it("builds lineToIndex properly", function () { 24 | assert.deepEqual( 25 | LineColumnFinder(testString).lineToIndex, 26 | [0, 8, 23, 29, 36] 27 | ); 28 | }); 29 | it("can be shorthand for #fromIndex", function () { 30 | assert.deepEqual(LineColumnFinder(testString, 15), { line: 2, col: 8 }); 31 | }); 32 | it("can be called without arguments", function () { 33 | assert(LineColumnFinder() instanceof LineColumnFinder); 34 | }); 35 | }); 36 | 37 | describe("#fromIndex", function () { 38 | 39 | context("with 1-origin", function () { 40 | var lineColumn = LineColumnFinder(testString); 41 | 42 | it("returns line-column for the first line", function () { 43 | assert.deepEqual(lineColumn.fromIndex(3), { line: 1, col: 4 }); 44 | }); 45 | it("returns line-column for the middle line", function () { 46 | assert.deepEqual(lineColumn.fromIndex(15), { line: 2, col: 8 }); 47 | }); 48 | it("returns line-column for the line containing wide chars", function () { 49 | assert.deepEqual(lineColumn.fromIndex(33), { line: 4, col: 5 }); 50 | }); 51 | it("returns line-column for the last line", function () { 52 | assert.deepEqual(lineColumn.fromIndex(43), { line: 5, col: 8 }); 53 | }); 54 | it("returns line-column for the last character", function () { 55 | assert.deepEqual(lineColumn.fromIndex(48), { line: 5, col: 13 }); 56 | }); 57 | 58 | it("returns null for an index < 1", function () { 59 | assert(lineColumn.fromIndex(-1) === null); 60 | }); 61 | it("returns null for an index >= str.length", function () { 62 | assert(lineColumn.fromIndex(49) === null); 63 | }); 64 | it("returns null for a NaN index", function () { 65 | assert(lineColumn.fromIndex(NaN) === null); 66 | }); 67 | }); 68 | 69 | context("with 0-origin", function () { 70 | var lineColumn = LineColumnFinder(testString, { origin: 0 }); 71 | 72 | it("returns line-column for the first line", function () { 73 | assert.deepEqual(lineColumn.fromIndex(3), { line: 0, col: 3 }); 74 | }); 75 | it("returns line-column for the middle line", function () { 76 | assert.deepEqual(lineColumn.fromIndex(15), { line: 1, col: 7 }); 77 | }); 78 | it("returns line-column for the line containing wide chars", function () { 79 | assert.deepEqual(lineColumn.fromIndex(33), { line: 3, col: 4 }); 80 | }); 81 | it("returns line-column for the last line", function () { 82 | assert.deepEqual(lineColumn.fromIndex(43), { line: 4, col: 7 }); 83 | }); 84 | it("returns line-column for the last character", function () { 85 | assert.deepEqual(lineColumn.fromIndex(48), { line: 4, col: 12 }); 86 | }); 87 | 88 | it("returns null for an index < 0", function () { 89 | assert(lineColumn.fromIndex(-1) === null); 90 | }); 91 | it("returns null for an index >= str.length", function () { 92 | assert(lineColumn.fromIndex(49) === null); 93 | }); 94 | it("returns null for a NaN index", function () { 95 | assert(lineColumn.fromIndex(NaN) === null); 96 | }); 97 | }); 98 | 99 | }); 100 | 101 | describe("#toIndex", function () { 102 | 103 | context("with 1-origin", function () { 104 | var lineColumn = LineColumnFinder(testString); 105 | 106 | it("returns an index for the first line", function () { 107 | assert(lineColumn.toIndex(1, 4) === 3); 108 | }); 109 | it("returns an index for the middle line", function () { 110 | assert(lineColumn.toIndex(2, 8) === 15); 111 | }); 112 | it("returns an index for the line containing wide chars", function () { 113 | assert(lineColumn.toIndex(4, 5) === 33); 114 | }); 115 | it("returns an index for the last line", function () { 116 | assert(lineColumn.toIndex(5, 8) === 43); 117 | }); 118 | it("returns an index for the last character", function () { 119 | assert(lineColumn.toIndex(5, 13) === 48); 120 | }); 121 | it("allows column == line.length", function () { 122 | assert(lineColumn.toIndex(1, 8) === 7); 123 | }); 124 | 125 | it("accepts an Object of { line, col }", function () { 126 | assert(lineColumn.toIndex({ line: 2, col: 8 }) === 15); 127 | }); 128 | it("accepts an Object of { line, column }", function () { 129 | assert(lineColumn.toIndex({ line: 2, column: 8 }) === 15); 130 | }); 131 | it("accepts an Array of [ line, col ]", function () { 132 | assert(lineColumn.toIndex([2, 8]) === 15); 133 | }); 134 | 135 | it("returns -1 for line < 1", function () { 136 | assert(lineColumn.toIndex(0, 4) === -1); 137 | }); 138 | it("returns -1 for column < 1", function () { 139 | assert(lineColumn.toIndex(2, 0) === -1); 140 | }); 141 | it("returns -1 for line >= lines.length", function () { 142 | assert(lineColumn.toIndex(6, 1) === -1); 143 | }); 144 | it("returns -1 for column >= line.length", function () { 145 | assert(lineColumn.toIndex(1, 9) === -1); 146 | }); 147 | it("returns -1 for line + column >= str.length", function () { 148 | assert(lineColumn.toIndex(5, 14) === -1); 149 | }); 150 | 151 | it("returns -1 for missing column", function () { 152 | assert(lineColumn.toIndex(1) === -1); 153 | }); 154 | it("returns -1 for NaN line", function () { 155 | assert(lineColumn.toIndex(NaN, 1) === -1); 156 | }); 157 | it("returns -1 for NaN column", function () { 158 | assert(lineColumn.toIndex(1, NaN) === -1); 159 | }); 160 | }); 161 | 162 | context("with 0-origin", function () { 163 | var lineColumn = LineColumnFinder(testString, { origin: 0 }); 164 | 165 | it("returns an index for the first line", function () { 166 | assert(lineColumn.toIndex(0, 3) === 3); 167 | }); 168 | it("returns an index for the middle line", function () { 169 | assert(lineColumn.toIndex(1, 7) === 15); 170 | }); 171 | it("returns an index for the line containing wide chars", function () { 172 | assert(lineColumn.toIndex(3, 4) === 33); 173 | }); 174 | it("returns an index for the last line", function () { 175 | assert(lineColumn.toIndex(4, 7) === 43); 176 | }); 177 | it("returns an index for the first character", function () { 178 | assert(lineColumn.toIndex(0, 0) === 0); 179 | }); 180 | it("returns an index for the last character", function () { 181 | assert(lineColumn.toIndex(4, 12) === 48); 182 | }); 183 | it("allows column == line.length", function () { 184 | assert(lineColumn.toIndex(0, 7) === 7); 185 | }); 186 | 187 | it("accepts an Object of { line, col }", function () { 188 | assert(lineColumn.toIndex({ line: 1, col: 7 }) === 15); 189 | }); 190 | it("accepts an Object of { line, column }", function () { 191 | assert(lineColumn.toIndex({ line: 1, column: 7 }) === 15); 192 | }); 193 | it("accepts an Array of [ line, col ]", function () { 194 | assert(lineColumn.toIndex([1, 7]) === 15); 195 | }); 196 | it("returns an index for { line: 0, col: 0 }", function () { 197 | assert(lineColumn.toIndex({ line: 0, col: 0 }) === 0); 198 | }); 199 | it("returns an index for { line: 0, column: 0 }", function () { 200 | assert(lineColumn.toIndex({ line: 0, column: 0 }) === 0); 201 | }); 202 | it("returns an index for [ 0, 0 ]", function () { 203 | assert(lineColumn.toIndex([0, 0]) === 0); 204 | }); 205 | 206 | it("returns -1 for line < 0", function () { 207 | assert(lineColumn.toIndex(-1, 3) === -1); 208 | }); 209 | it("returns -1 for column < 0", function () { 210 | assert(lineColumn.toIndex(1, -1) === -1); 211 | }); 212 | it("returns -1 for line >= lines.length", function () { 213 | assert(lineColumn.toIndex(5, 0) === -1); 214 | }); 215 | it("returns -1 for column >= line.length", function () { 216 | assert(lineColumn.toIndex(0, 8) === -1); 217 | }); 218 | it("returns -1 for line + column >= str.length", function () { 219 | assert(lineColumn.toIndex(4, 13) === -1); 220 | }); 221 | 222 | it("returns -1 for missing column", function () { 223 | assert(lineColumn.toIndex(1) === -1); 224 | }); 225 | it("returns -1 for NaN line", function () { 226 | assert(lineColumn.toIndex(NaN, 1) === -1); 227 | }); 228 | it("returns -1 for NaN column", function () { 229 | assert(lineColumn.toIndex(1, NaN) === -1); 230 | }); 231 | }); 232 | 233 | }); 234 | 235 | }); 236 | -------------------------------------------------------------------------------- /test/mocha.opts: -------------------------------------------------------------------------------- 1 | --require intelli-espower-loader -------------------------------------------------------------------------------- /wercker.yml: -------------------------------------------------------------------------------- 1 | # This references the default nodejs container from 2 | # the Docker Hub: https://registry.hub.docker.com/_/node/ 3 | # If you want Nodesource's container you would reference nodesource/node 4 | # Read more about containers on our dev center 5 | # http://devcenter.wercker.com/docs/containers/index.html 6 | box: node 7 | # This is the build pipeline. Pipelines are the core of wercker 8 | # Read more about pipelines on our dev center 9 | # http://devcenter.wercker.com/docs/pipelines/index.html 10 | 11 | # You can also use services such as databases. Read more on our dev center: 12 | # http://devcenter.wercker.com/docs/services/index.html 13 | # services: 14 | # - postgres 15 | # http://devcenter.wercker.com/docs/services/postgresql.html 16 | 17 | # - mongodb 18 | # http://devcenter.wercker.com/docs/services/mongodb.html 19 | build: 20 | # The steps that will be executed on build 21 | # Steps make up the actions in your pipeline 22 | # Read more about steps on our dev center: 23 | # http://devcenter.wercker.com/docs/steps/index.html 24 | steps: 25 | # A step that executes `npm install` command 26 | - npm-install 27 | 28 | - script: 29 | name: npm run test-ci 30 | code: npm run test-ci 31 | 32 | # A custom script step, name value is used in the UI 33 | # and the code value contains the command that get executed 34 | - script: 35 | name: echo nodejs information 36 | code: | 37 | echo "node version $(node -v) running" 38 | echo "npm version $(npm -v) running" 39 | --------------------------------------------------------------------------------