pax_global_header00006660000000000000000000000064131103734030014505gustar00rootroot0000000000000052 comment=fbccf96847a2cce145dd77a31fd7b9c7d21583f2 locate-character-v2.0.1-fbccf96847a2cce145dd77a31fd7b9c7d21583f2/000077500000000000000000000000001311037340300227675ustar00rootroot00000000000000locate-character-v2.0.1-fbccf96847a2cce145dd77a31fd7b9c7d21583f2/.gitignore000066400000000000000000000000341311037340300247540ustar00rootroot00000000000000.DS_Store node_modules dist locate-character-v2.0.1-fbccf96847a2cce145dd77a31fd7b9c7d21583f2/CHANGELOG.md000066400000000000000000000004301311037340300245750ustar00rootroot00000000000000# locate-character changelog ## 2.0.1 * Port to TypeScript, add typings (no change in functionality) ## 2.0.0 * BREAKING: `startIndex` must be passed as a property of `options`, not as a standalone argument * Support `offsetLine` and `offsetColumn` ## 1.0.0 * First release locate-character-v2.0.1-fbccf96847a2cce145dd77a31fd7b9c7d21583f2/README.md000066400000000000000000000032541311037340300242520ustar00rootroot00000000000000# locate-character Get the line and column number of a particular character in a string. ## Installation `npm install locate-character`, or get it from [unpkg.com/locate-character](https://unpkg.com/locate-character). ## Usage To search for a particular character, using the index or a search string, use `locate`: ```js import { locate } from 'locate-character'; const sample = ` A flea and a fly in a flue Were imprisoned, so what could they do? Said the fly, "let us flee!" "Let us fly!" said the flea. So they flew through a flaw in the flue. `.trim(); // Using a character index const index = sample.indexOf( 'fly' ); locate( sample, index ); // -> { line: 0, column: 13, character: 13 } // Using the string itself locate( sample, 'fly' ); // -> { line: 0, column: 13, character: 13 } // Using the string with a start index locate( sample, 'fly', { startIndex: 14 }); // -> { line: 2, column: 9, character: 76 } ``` If you will be searching the same string repeatedly, it's much faster if you use `getLocator`: ```js import { getLocator } from 'locate-character'; const locate = getLocator( sample ); let location = locate( 13 ); // -> { line: 0, column: 13, character: 13 } location = locate( 'fly', { startIndex: location.character + 1 }); // -> { line: 2, column: 9, character: 76 } location = locate( 'fly', { startIndex: location.character + 1 }); // -> { line: 3, column: 8, character: 104 } ``` In some situations (for example, dealing with sourcemaps), you need one-based line numbers: ```js getLocator( sample, { offsetLine: 1 }); locate( sample, { offsetLine: 1 }); ``` There's also an `offsetColumn` option which is less useful in real-world situations. ## License MIT locate-character-v2.0.1-fbccf96847a2cce145dd77a31fd7b9c7d21583f2/package.json000066400000000000000000000020231311037340300252520ustar00rootroot00000000000000{ "name": "locate-character", "version": "2.0.1", "description": "Get the line and column number of a specific character in a string", "main": "dist/locate-character.umd.js", "jsnext:main": "dist/locate-character.es.js", "module": "dist/locate-character.es.js", "scripts": { "test": "mocha", "pretest": "npm run build", "build": "rollup -c", "prepublish": "npm test" }, "files": [ "dist", "README.md" ], "repository": { "type": "git", "url": "git+https://gitlab.com/Rich-Harris/locate-character.git" }, "keywords": [ "string", "character", "locate", "line", "column", "location" ], "author": "Rich Harris", "license": "MIT", "bugs": { "url": "https://gitlab.com/Rich-Harris/locate-character/issues" }, "homepage": "https://gitlab.com/Rich-Harris/locate-character#README", "devDependencies": { "mocha": "^3.0.1", "rollup": "^0.34.7", "rollup-plugin-typescript": "^0.8.1", "typescript": "^2.3.2" }, "types": "./types.d.ts" } locate-character-v2.0.1-fbccf96847a2cce145dd77a31fd7b9c7d21583f2/rollup.config.js000066400000000000000000000005131311037340300261050ustar00rootroot00000000000000import typescript from 'rollup-plugin-typescript'; export default { entry: 'src/index.ts', moduleName: 'locateCharacter', plugins: [ typescript({ typescript: require('typescript') }) ], targets: [ { dest: 'dist/locate-character.es.js', format: 'es' }, { dest: 'dist/locate-character.umd.js', format: 'umd' } ] }; locate-character-v2.0.1-fbccf96847a2cce145dd77a31fd7b9c7d21583f2/src/000077500000000000000000000000001311037340300235565ustar00rootroot00000000000000locate-character-v2.0.1-fbccf96847a2cce145dd77a31fd7b9c7d21583f2/src/index.ts000066400000000000000000000036221311037340300252400ustar00rootroot00000000000000interface Options { offsetLine?: number offsetColumn?: number startIndex?: number } interface Range { start: number end: number line: number } interface Location { line: number column: number character: number } export function getLocator ( source: string, options: Options = {} ) { const offsetLine = options.offsetLine || 0; const offsetColumn = options.offsetColumn || 0; let originalLines = source.split( '\n' ); let start = 0; let lineRanges = originalLines.map( ( line, i ) => { const end = start + line.length + 1; const range: Range = { start, end, line: i }; start = end; return range; }); let i = 0; function rangeContains ( range: Range, index: number ) { return range.start <= index && index < range.end; } function getLocation ( range: Range, index: number ): Location { return { line: offsetLine + range.line, column: offsetColumn + index - range.start, character: index }; } function locate ( search: string, startIndex?: number ): Location function locate ( search: number ): Location function locate ( search: any, startIndex?: number ): Location { if ( typeof search === 'string' ) { search = source.indexOf( search, startIndex || 0 ); } let range = lineRanges[i]; const d = search >= range.end ? 1 : -1; while ( range ) { if ( rangeContains( range, search ) ) return getLocation( range, search ); i += d; range = lineRanges[i]; } }; return locate; } function locate ( source: string, search: string, options?: Options ): Location function locate ( source: string, search: number, options?: Options ): Location function locate ( source: string, search: any, options?: Options ): Location { if ( typeof options === 'number' ) { throw new Error( 'locate takes a { startIndex, offsetLine, offsetColumn } object as the third argument' ); } return getLocator( source, options )( search, options && options.startIndex ); } export { locate }; locate-character-v2.0.1-fbccf96847a2cce145dd77a31fd7b9c7d21583f2/test/000077500000000000000000000000001311037340300237465ustar00rootroot00000000000000locate-character-v2.0.1-fbccf96847a2cce145dd77a31fd7b9c7d21583f2/test/test.js000066400000000000000000000045601311037340300252700ustar00rootroot00000000000000const fs = require( 'fs' ); const path = require( 'path' ); const assert = require( 'assert' ); const { locate, getLocator } = require( '..' ); const sample = ` A flea and a fly in a flue Were imprisoned, so what could they do? Said the fly, "let us flee!" "Let us fly!" said the flea. So they flew through a flaw in the flue. `.trim(); describe( 'locate-character', () => { describe( 'getLocator', () => { const locator = getLocator( sample ); it( 'returns a function', () => { assert.equal( typeof getLocator( sample ), 'function' ); }); it( 'locates by character index', () => { assert.deepEqual( locator( 0 ), { line: 0, column: 0, character: 0 }); assert.deepEqual( locator( 1 ), { line: 0, column: 1, character: 1 }); assert.deepEqual( locator( 76 ), { line: 2, column: 9, character: 76 }); }); it( 'respects offsetLine: x and offsetColumn: x', () => { const locator = getLocator( sample, { offsetLine: 2, offsetColumn: 2 }); assert.deepEqual( locator( 0 ), { line: 2, column: 2, character: 0 } ); }); it( 'locates by search string', () => { assert.deepEqual( locator( 'fly' ), { line: 0, column: 13, character: 13 }); }); it( 'locates by search string with startIndex', () => { let location = locator( 'fly' ); assert.deepEqual( location, { line: 0, column: 13, character: 13 }); location = locator( 'fly', location.character + 1 ); assert.deepEqual( location, { line: 2, column: 9, character: 76 }); location = locator( 'fly', location.character + 1 ); assert.deepEqual( location, { line: 3, column: 8, character: 104 }); }); }); describe( 'locate', () => { it( 'locates a character by index', () => { assert.deepEqual( locate( sample, 13 ), { line: 0, column: 13, character: 13 }); }); it( 'locates a character by string', () => { assert.deepEqual( locate( sample, 'fly' ), { line: 0, column: 13, character: 13 }); }); it( 'locates a character by string with startIndex', () => { assert.deepEqual( locate( sample, 'fly', { startIndex: 14 }), { line: 2, column: 9, character: 76 }); assert.deepEqual( locate( sample, 'fly', { startIndex: 77 }), { line: 3, column: 8, character: 104 }); }); it( 'respects offsetLine: x and offsetColumn: x', () => { assert.deepEqual( locate( sample, 13, { offsetLine: 2, offsetColumn: 2 }), { line: 2, column: 15, character: 13 } ); }); }); }); locate-character-v2.0.1-fbccf96847a2cce145dd77a31fd7b9c7d21583f2/tsconfig.json000066400000000000000000000004451311037340300255010ustar00rootroot00000000000000{ "compilerOptions": { "noImplicitAny": true, "diagnostics": true, "noImplicitThis": true, "noEmitOnError": true, "lib": ["es5", "es6"] }, "target": "ES5", "include": [ "src" ], "exclude": [ "node_modules" ] }locate-character-v2.0.1-fbccf96847a2cce145dd77a31fd7b9c7d21583f2/types.d.ts000066400000000000000000000010551311037340300247260ustar00rootroot00000000000000interface Options { offsetLine?: number offsetColumn?: number startIndex?: number } export interface Location { line: number column: number character: number } export function locate ( source: string, search: string, options?: Options ): Location export function locate ( source: string, search: number, options?: Options ): Location export function getLocator ( source: string, options?: Options ): ( search: string, startIndex?: number ) => Location export function getLocator ( source: string, options?: Options ): ( search: number ) => Location