├── .babelrc ├── .editorconfig ├── .eslintrc ├── .gitattributes ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── gulpfile.js ├── lib └── index.js ├── package.json └── test └── index.js /.babelrc: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | charset = utf-8 7 | trim_trailing_whitespace = true 8 | insert_final_newline = true 9 | 10 | [*.md] 11 | trim_trailing_whitespace = false 12 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "eslint:recommended", 3 | "env": { 4 | "node": true, 5 | "mocha": true, 6 | "es6": true 7 | }, 8 | "rules": { 9 | "array-bracket-spacing": [ 10 | 2, 11 | "never" 12 | ], 13 | "brace-style": [ 14 | 2, 15 | "1tbs" 16 | ], 17 | "consistent-return": 0, 18 | "indent": [ 19 | 2, 20 | 2 21 | ], 22 | "no-multiple-empty-lines": [ 23 | 2, 24 | { 25 | "max": 2 26 | } 27 | ], 28 | "no-use-before-define": [ 29 | 2, 30 | "nofunc" 31 | ], 32 | "one-var": [ 33 | 2, 34 | "never" 35 | ], 36 | "quote-props": [ 37 | 2, 38 | "as-needed" 39 | ], 40 | "quotes": [ 41 | 2, 42 | "single" 43 | ], 44 | "space-after-keywords": [ 45 | 2, 46 | "always" 47 | ], 48 | "space-before-function-paren": [ 49 | 2, 50 | { 51 | "anonymous": "always", 52 | "named": "never" 53 | } 54 | ], 55 | "space-in-parens": [ 56 | 2, 57 | "never" 58 | ], 59 | "strict": [ 60 | 2, 61 | "global" 62 | ], 63 | "curly": [ 64 | 2, 65 | "all" 66 | ], 67 | "eol-last": 2, 68 | "key-spacing": [ 69 | 2, 70 | { 71 | "beforeColon": false, 72 | "afterColon": true 73 | } 74 | ], 75 | "no-eval": 2, 76 | "no-with": 2, 77 | "space-infix-ops": 2, 78 | "dot-notation": [ 79 | 2, 80 | { 81 | "allowKeywords": true 82 | } 83 | ], 84 | "eqeqeq": 2, 85 | "no-alert": 2, 86 | "no-caller": 2, 87 | "no-empty-label": 2, 88 | "no-extend-native": 2, 89 | "no-extra-bind": 2, 90 | "no-implied-eval": 2, 91 | "no-iterator": 2, 92 | "no-label-var": 2, 93 | "no-labels": 2, 94 | "no-lone-blocks": 2, 95 | "no-loop-func": 2, 96 | "no-multi-spaces": 2, 97 | "no-multi-str": 2, 98 | "no-native-reassign": 2, 99 | "no-new": 2, 100 | "no-new-func": 2, 101 | "no-new-wrappers": 2, 102 | "no-octal-escape": 2, 103 | "no-proto": 2, 104 | "no-return-assign": 2, 105 | "no-script-url": 2, 106 | "no-sequences": 2, 107 | "no-unused-expressions": 2, 108 | "yoda": 2, 109 | "no-shadow": 2, 110 | "no-shadow-restricted-names": 2, 111 | "no-undef-init": 2, 112 | "camelcase": 2, 113 | "comma-spacing": 2, 114 | "new-cap": 2, 115 | "new-parens": 2, 116 | "no-array-constructor": 2, 117 | "no-extra-parens": 2, 118 | "no-new-object": 2, 119 | "no-spaced-func": 2, 120 | "no-trailing-spaces": 2, 121 | "no-underscore-dangle": 2, 122 | "semi": 2, 123 | "semi-spacing": [ 124 | 2, 125 | { 126 | "before": false, 127 | "after": true 128 | } 129 | ], 130 | "space-return-throw-case": 2 131 | }, 132 | "ecmaFeatures": { 133 | "modules": true 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | coverage 3 | dist 4 | .DS_Store 5 | npm-debug.log 6 | .idea 7 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - '0.12' 4 | - '4' 5 | - '5' 6 | script: "npm run test" 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Patil, Omkar (https://github.com/ospatil) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # string-search 2 | [![NPM version][npm-image]][npm-url] [![Build Status][travis-image]][travis-url] [![Dependency Status][daviddm-image]][daviddm-url] [![Coverage Status][coveralls-image]][coveralls-url] 3 | > Node module that carries out regex search on given multi-line string and returns match information. 4 | 5 | ## Features 6 | [string-search](https://github.com/ospatil/string-search) finds and returns match information for each match. 7 | - Accepts a multi-line string and regular expression in string format. 8 | - Searches the given string with provided regular expression. 9 | - Returns a promise that eventually resolves to an array. The array contains match objects each having following attributes - 10 | - line - line number(s) that the matched result was found on. 11 | - term - the search term. 12 | - text - the entire line(s) that the matched result was found in. 13 | 14 | ## Getting Started 15 | Install with [NPM](https://www.npmjs.com) - `npm install --save string-search` 16 | 17 | ## Usage 18 | ```js 19 | var stringSearcher = require('string-search'); 20 | 21 | stringSearcher.find('This is the string to search text in', 'string') 22 | .then(function(resultArr) { 23 | //resultArr => [ {line: 1, term: 'string', text: 'This is the string to search text in'} ] 24 | }); 25 | ``` 26 | 27 | ## API 28 | ### stringSearcher.find(targetString, regex) 29 | 30 | Name | Type | Argument | Description 31 | -------------|----------------|--------------|------------ 32 | targetString | `string` | `` | target string to be searched. Can be multi-line(can contain line breaks). 33 | regex | `string` | `` | a string in regular expression format to search. 34 | 35 | Returns **promise** that resolves to an array of objects containing following attributes - 36 | 37 | Name | Type | Description 38 | -----|-----------| ------------ 39 | line | `integer` | line number that the matched result was found on. 40 | term | `string` | The search term 41 | text | `string` | the entire line(s) that the matched result was found in. 42 | 43 | The **promise** is rejected in case of missing or invalid arguments. 44 | 45 | ## Contributing 46 | In lieu of a formal style guide, take care to maintain the existing coding style. Add unit tests for any new or changed functionality. 47 | 48 | ## Notes 49 | Heavily inspired by [lineder](https://github.com/jasonbellamy/lineder). I needed file reading part separated from text searching part 50 | so that a file can be read only once and multiple searches can be carried out on it. I also used promise to return results instead of a callback. 51 | 52 | ## License 53 | Copyright © 2015 [Omkar Patil](https://github.com/ospatil) 54 | 55 | Licensed under the MIT license. 56 | 57 | [npm-image]: https://badge.fury.io/js/string-search.svg?style=flat-square 58 | [npm-url]: https://npmjs.org/string-search 59 | [travis-image]: https://travis-ci.org/ospatil/string-search.svg?branch=master&style=flat-square 60 | [travis-url]: https://travis-ci.org/ospatil/string-search 61 | [daviddm-image]: https://david-dm.org/ospatil/string-search.svg?theme=shields.io&style=flat-square 62 | [daviddm-url]: https://david-dm.org/ospatil/string-search 63 | [coveralls-image]: https://img.shields.io/coveralls/ospatil/string-search.svg?style=flat-square 64 | [coveralls-url]: https://coveralls.io/github/ospatil/string-search?branch=master 65 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var path = require('path'); 3 | var gulp = require('gulp'); 4 | var eslint = require('gulp-eslint'); 5 | var excludeGitignore = require('gulp-exclude-gitignore'); 6 | var mocha = require('gulp-mocha'); 7 | var istanbul = require('gulp-istanbul'); 8 | var plumber = require('gulp-plumber'); 9 | var coveralls = require('gulp-coveralls'); 10 | var babel = require('gulp-babel'); 11 | var del = require('del'); 12 | var isparta = require('isparta'); 13 | 14 | // Initialize the babel transpiler so ES2015 files gets compiled 15 | // when they're loaded 16 | require('babel-core/register'); 17 | 18 | var paths = { 19 | es6: ['lib/**/*.js'] 20 | }; 21 | 22 | gulp.task('static', function () { 23 | return gulp.src(paths.es6) 24 | .pipe(excludeGitignore()) 25 | .pipe(eslint()) 26 | .pipe(eslint.format()) 27 | .pipe(eslint.failAfterError()); 28 | }); 29 | 30 | gulp.task('pre-test', function () { 31 | return gulp.src(paths.es6) 32 | .pipe(istanbul({ 33 | includeUntested: true 34 | , instrumenter: isparta.Instrumenter 35 | })) 36 | .pipe(istanbul.hookRequire()); 37 | }); 38 | 39 | gulp.task('test', ['pre-test'], function (cb) { 40 | var mochaErr; 41 | 42 | gulp.src('test/**/*.js') 43 | .pipe(plumber()) 44 | .pipe(mocha({reporter: 'spec'})) 45 | .on('error', function (err) { 46 | console.log(err); 47 | mochaErr = err; 48 | }) 49 | .pipe(istanbul.writeReports()) 50 | .on('end', function () { 51 | cb(mochaErr); 52 | }); 53 | }); 54 | 55 | gulp.task('coveralls', ['test'], function () { 56 | if (!process.env.CI) { 57 | return; 58 | } 59 | 60 | return gulp.src(path.join(__dirname, 'coverage/lcov.info')) 61 | .pipe(coveralls()); 62 | }); 63 | 64 | gulp.task('babel', ['clean'], function () { 65 | return gulp.src(paths.es6) 66 | .pipe(babel()) 67 | .pipe(gulp.dest('dist')); 68 | }); 69 | 70 | gulp.task('clean', function () { 71 | return del('dist'); 72 | }); 73 | 74 | gulp.task('prepublish', ['babel']); 75 | 76 | gulp.task('default', ['static', 'test', 'coveralls']); 77 | 78 | gulp.task('watch', function() { 79 | gulp.watch(paths.es6, ['babel']); 80 | }); 81 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * string-search 3 | * https://github.com/ospatil/string-search 4 | * 5 | * Copyright (c) 2015 Omkar Patil 6 | * Licensed under the MIT license. 7 | */ 8 | import { Promise } from 'bluebird'; 9 | 10 | export function find(...args) { 11 | return new Promise((resolve, reject) => { 12 | if (args.length !== 2) { 13 | reject('You must provide all arguments'); 14 | } 15 | const [targetStr, patternStr] = args; 16 | const results = []; 17 | const pattern = new RegExp(patternStr, 'gi'); 18 | 19 | targetStr.split('\n').forEach((value, index) => { 20 | if (value.match(pattern)) { 21 | results.push({line: index + 1, text: value, term: patternStr}); 22 | } 23 | }); 24 | resolve(results); 25 | }); 26 | } 27 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "string-search", 3 | "version": "1.2.0", 4 | "description": "Node module for searching multi-line string using regex", 5 | "homepage": "https://github.com/ospatil/string-search", 6 | "author": { 7 | "name": "Omkar Patil", 8 | "email": "ospatil@gmail.com", 9 | "url": "https://github.com/ospatil" 10 | }, 11 | "files": [ 12 | "dist" 13 | ], 14 | "main": "dist/index.js", 15 | "keywords": [ 16 | "search", 17 | "text search", 18 | "regex", 19 | "node" 20 | ], 21 | "repository": "https://github.com/ospatil/string-search.git", 22 | "devDependencies": { 23 | "babel-core": "^5.5.0", 24 | "chai": "3.4.0", 25 | "chai-as-promised": "5.1.0", 26 | "del": "^2.0.2", 27 | "gulp": "^3.6.0", 28 | "gulp-babel": "^5.1.0", 29 | "gulp-coveralls": "^0.1.0", 30 | "gulp-eslint": "^1.0.0", 31 | "gulp-exclude-gitignore": "^1.0.0", 32 | "gulp-istanbul": "^0.9.0", 33 | "gulp-mocha": "^2.0.0", 34 | "gulp-plumber": "^1.0.0", 35 | "isparta": "^3.0.3" 36 | }, 37 | "scripts": { 38 | "prepublish": "gulp prepublish", 39 | "test": "gulp" 40 | }, 41 | "license": "MIT", 42 | "dependencies": { 43 | "bluebird": "3.0.5" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /test/index.js: -------------------------------------------------------------------------------- 1 | import { find } from '../lib'; 2 | import chai from 'chai'; 3 | import chaiAsPromised from 'chai-as-promised'; 4 | 5 | chai.use(chaiAsPromised); 6 | 7 | const expect = chai.expect; 8 | 9 | const multipleMatchStr = 10 | ` 11 | 12 | 13 | 14 | Document 15 | 16 | 17 |
My class div
18 |
Another div
19 | My class span 20 | 21 | `; 22 | 23 | describe('string-search', function () { 24 | it('should reject promise if called without arguments', function () { 25 | return expect(find()).to.be.eventually.rejected; 26 | }); 27 | 28 | it('should reject promise if called with illegal string to be searched argument', function () { 29 | return expect(find(undefined, 'one')).to.be.eventually.rejected; 30 | }); 31 | 32 | it('should return match even if the target string does not contain newline', function () { 33 | const result = find('A single liner string', 'li'); 34 | return expect(result).to.eventually.have.length(1); 35 | }); 36 | 37 | it('should return zero length array if no match found', function () { 38 | const result = find('A single liner string', 'qu'); 39 | return expect(result).to.eventually.have.length(0); 40 | }); 41 | 42 | it('should return multiple matches if found', function () { 43 | const result = find(multipleMatchStr, 'class="my-'); 44 | return expect(result).to.eventually.have.length(2); 45 | }); 46 | 47 | it('should return understand the usual escape characters', function () { 48 | const result = find(multipleMatchStr, '\/span'); 49 | return expect(result).to.eventually.have.length(1); 50 | return expect(result).to.eventually.deep.equal({ line: 10, text: ' My class span', term: '/span' }); 51 | }); 52 | }); 53 | --------------------------------------------------------------------------------