package/0000755000175000017500000000000013736040206012030 5ustar xavierxavierpackage/src/0000755000175000017500000000000013736040104012614 5ustar xavierxavierpackage/src/index.ts0000644000175000017500000000362213736040104014276 0ustar xavierxavierinterface 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 }; package/tsconfig.json0000644000175000017500000000044513736040104014537 0ustar xavierxavier{ "compilerOptions": { "noImplicitAny": true, "diagnostics": true, "noImplicitThis": true, "noEmitOnError": true, "lib": ["es5", "es6"] }, "target": "ES5", "include": [ "src" ], "exclude": [ "node_modules" ] }package/test/0000755000175000017500000000000013736040104013004 5ustar xavierxavierpackage/test/test.js0000644000175000017500000000456013736040104014326 0ustar xavierxavierconst 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 } ); }); }); }); package/CHANGELOG.md0000644000175000017500000000060313736040206013640 0ustar xavierxavier# locate-character changelog ## 2.0.5 * Fix incorrect `pkg.repository` ## 2.0.4 * Fix typings ## 2.0.2-3 * Add typings to package ## 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 package/package.json0000644000175000017500000000200113736040206014307 0ustar xavierxavier{ "name": "locate-character", "version": "2.0.5", "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 && tsc", "prepublish": "npm test" }, "files": [ "dist/*.js", "dist/**/*.d.ts", "README.md" ], "repository": "Rich-Harris/locate-character", "keywords": [ "string", "character", "locate", "line", "column", "location" ], "author": "Rich Harris", "license": "MIT", "bugs": { "url": "https://github.com/Rich-Harris/locate-character/issues" }, "homepage": "https://github.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": "./dist/types/index.d.ts" } package/.gitignore0000644000175000017500000000003413736040104014012 0ustar xavierxavier.DS_Store node_modules dist package/README.md0000644000175000017500000000325413735253220013314 0ustar xavierxavier# 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 package/rollup.config.js0000644000175000017500000000051313736040104015143 0ustar xavierxavierimport 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' } ] }; package/dist/0000755000175000017500000000000013736040206012773 5ustar xavierxavierpackage/dist/types/0000755000175000017500000000000013736040206014137 5ustar xavierxavierpackage/dist/types/index.d.ts0000644000175000017500000000104513736040206016040 0ustar xavierxavierexport interface Options { offsetLine?: number; offsetColumn?: number; startIndex?: number; } export interface Location { line: number; column: number; character: number; } export declare function getLocator(source: string, options?: Options): { (search: string, startIndex?: number): Location; (search: number): Location; }; declare function locate(source: string, search: string, options?: Options): Location; declare function locate(source: string, search: number, options?: Options): Location; export { locate }; package/types.d.ts0000644000175000017500000000105513736040104013764 0ustar xavierxavierinterface 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