replace-last
Advanced tools
Comparing version 1.1.0 to 1.2.0
@@ -7,2 +7,32 @@ 'use strict'; | ||
var regexReplaceLast = function(str, pattern, replacement) { | ||
// Official MDN polyfill https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/flags | ||
// for Node.js v4 | ||
/* istanbul ignore next */ | ||
if (RegExp.prototype.flags === undefined) { | ||
Object.defineProperty(RegExp.prototype, 'flags', { | ||
configurable: true, | ||
get: function() { | ||
return this.toString().match(/[gimuy]*$/)[0]; | ||
} | ||
}); | ||
} | ||
var flags = (pattern.flags.indexOf('g') === -1) ? pattern.flags + 'g' : pattern.flags; | ||
pattern = new RegExp(pattern.source, flags); | ||
return str.replace(pattern, function(/* args expanded below */) { | ||
var match = arguments[0]; | ||
var p = Array.prototype.slice.call(arguments, 1, arguments.length - 2); | ||
var offset = arguments[arguments.length - 2]; | ||
var str = arguments[arguments.length - 1]; | ||
var follow = str.slice(offset); | ||
var isLast = follow.match(pattern).length === 1; | ||
if (!isLast) return match; | ||
if (!p.length) return replacement; | ||
for (var i = 0; i < p.length; i++) { | ||
match = strReplaceLast(match, p[i], replacement); | ||
} | ||
return match; | ||
}); | ||
}; | ||
var strReplaceLast = function(str, pattern, replacement) { | ||
@@ -16,35 +46,13 @@ var i = str.lastIndexOf(pattern); | ||
var regexReplaceLast = function(str, pattern, replacement) { | ||
pattern = new RegExp(pattern.source, 'g'); | ||
return str.replace(pattern, function(match, offset, str) { | ||
var follow = str.slice(offset); | ||
var isLast = follow.match(pattern).length === 1; | ||
return (isLast) ? replacement : match; | ||
}); | ||
}; | ||
var replaceLast = function(str, pattern, replacement) { | ||
var orig = str; | ||
if (typeof(str) === 'number') str = str.toString(); | ||
if (typeof(pattern) === 'number') pattern = pattern.toString(); | ||
if (typeof(replacement) === 'number') replacement = replacement.toString(); | ||
if (typeof(str) !== 'string') return orig; | ||
if (typeof(replacement) !== 'string') return orig; | ||
var result; | ||
if (typeof(pattern) === 'string') { | ||
result = strReplaceLast(str, pattern, replacement); | ||
} else if (isRegex(pattern)) { | ||
result = regexReplaceLast(str, pattern, replacement); | ||
str = '' + str; | ||
if (typeof replacement === 'undefined') return str; | ||
if (isRegex(pattern)) { | ||
return regexReplaceLast(str, pattern, replacement); | ||
} else { | ||
return orig; | ||
pattern = '' + pattern; | ||
return strReplaceLast(str, pattern, replacement); | ||
} | ||
return (result === str) ? orig : result; | ||
}; | ||
module.exports = replaceLast; |
'use strict'; | ||
var _ = _ || require('lodash'); | ||
var chai = chai || require('chai'); | ||
@@ -11,4 +12,8 @@ var expect = chai.expect; | ||
it('number', function() { | ||
var result = replaceLast(778, 8, 7); | ||
expect(result).to.equal('777'); | ||
}); | ||
it('string', function() { | ||
// var replaceLast = require('replace-last'); | ||
var result = replaceLast('hello hello hello', 'hello', 'bye'); | ||
@@ -18,5 +23,9 @@ expect(result).to.equal('hello hello bye'); | ||
it('string', function() { | ||
// var replaceLast = require('replace-last'); | ||
var result = replaceLast('hello hello hello', /hello/, 'bye'); | ||
it('regex', function() { | ||
var result = replaceLast('hello hello hello', /he(ll)o/, 'rr'); | ||
expect(result).to.equal('hello hello herro'); | ||
}); | ||
it('RegExp', function() { | ||
var result = replaceLast('hello hello hello', RegExp('.ell.'), 'bye'); | ||
expect(result).to.equal('hello hello bye'); | ||
@@ -26,4 +35,27 @@ }); | ||
describe('number', function() { | ||
it('none', function() { | ||
var result = replaceLast(99, 7, 8); | ||
expect(result).to.equal('99'); | ||
}); | ||
it('single', function() { | ||
var result = replaceLast(9, 9, 8); | ||
expect(result).to.equal('8'); | ||
}); | ||
it('many', function() { | ||
var result = replaceLast(99, 9, 8); | ||
expect(result).to.equal('98'); | ||
}); | ||
}); | ||
describe('string', function() { | ||
it('none', function() { | ||
var result = replaceLast('hello hello', 'bonjour', 'bye'); | ||
expect(result).to.equal('hello hello'); | ||
}); | ||
it('single', function() { | ||
@@ -39,7 +71,2 @@ var result = replaceLast('hello', 'hello', 'bye'); | ||
it('none', function() { | ||
var result = replaceLast('hello hello', 'bonjour', 'bye'); | ||
expect(result).to.equal('hello hello'); | ||
}); | ||
it('contains regex chars', function() { | ||
@@ -51,24 +78,54 @@ var result = replaceLast('hello . hello . hello', '.', 'bye'); | ||
describe('number', function() { | ||
describe('regex', function() { | ||
it('none', function() { | ||
var result = replaceLast('hello hello', /bonjour/, 'bye'); | ||
expect(result).to.equal('hello hello'); | ||
}); | ||
it('single', function() { | ||
var result = replaceLast(9, 9, 8); | ||
expect(result).to.equal('8'); | ||
var result = replaceLast('hello', /hello/, 'bye'); | ||
expect(result).to.equal('bye'); | ||
}); | ||
it('many', function() { | ||
var result = replaceLast(99, 9, 8); | ||
expect(result).to.equal('98'); | ||
var result = replaceLast('hello hello', /hello/, 'bye'); | ||
expect(result).to.equal('hello bye'); | ||
}); | ||
it('none', function() { | ||
var result = replaceLast(99, 7, 8); | ||
expect(result).to.equal(99); | ||
it('many with g flag', function() { | ||
var result = replaceLast('hello hello', /hello/g, 'bye'); | ||
expect(result).to.equal('hello bye'); | ||
}); | ||
it('many with i flag', function() { | ||
var result = replaceLast('hello hello', /HELLO/i, 'bye'); | ||
expect(result).to.equal('hello bye'); | ||
}); | ||
it('matching groups', function() { | ||
var result = replaceLast('hello hello', /he(ll)o/, 'rr'); | ||
expect(result).to.equal('hello herro'); | ||
}); | ||
it('multiple matching groups', function() { | ||
var result = replaceLast('hello hello', /(ll)(o)/, 'r'); | ||
expect(result).to.equal('hello herr'); | ||
}); | ||
it('contains regex chars', function() { | ||
var result = replaceLast('hello . hello . hello', /./, 'bye'); | ||
expect(result).to.equal('hello . hello . hellbye'); | ||
}); | ||
}); | ||
describe('regex', function() { | ||
describe('RegExp', function() { | ||
it('none', function() { | ||
var result = replaceLast('hello hello', RegExp('bonjour'), 'bye'); | ||
expect(result).to.equal('hello hello'); | ||
}); | ||
it('single', function() { | ||
var result = replaceLast('hello', /hello/, 'bye'); | ||
var result = replaceLast('hello', RegExp('hello'), 'bye'); | ||
expect(result).to.equal('bye'); | ||
@@ -78,13 +135,34 @@ }); | ||
it('many', function() { | ||
var result = replaceLast('hello hello', /hello/, 'bye'); | ||
var result = replaceLast('hello hello', RegExp('hello'), 'bye'); | ||
expect(result).to.equal('hello bye'); | ||
}); | ||
it('none', function() { | ||
var result = replaceLast('hello hello', /bonjour/, 'bye'); | ||
expect(result).to.equal('hello hello'); | ||
it('many with g flag', function() { | ||
var result = replaceLast('hello hello', RegExp('hello', 'g'), 'bye'); | ||
expect(result).to.equal('hello bye'); | ||
}); | ||
it('many with i flag', function() { | ||
var result = replaceLast('hello hello', RegExp('HELLO', 'i'), 'bye'); | ||
expect(result).to.equal('hello bye'); | ||
}); | ||
it('many with invalid flag', function() { | ||
expect(function() { | ||
replaceLast('hello hello', RegExp('hello', 'q'), 'bye'); // eslint-disable-line no-invalid-regexp | ||
}).to.throw(SyntaxError); | ||
}); | ||
it('matching groups', function() { | ||
var result = replaceLast('hello hello', RegExp('he(ll)o'), 'rr'); | ||
expect(result).to.equal('hello herro'); | ||
}); | ||
it('multiple matching groups', function() { | ||
var result = replaceLast('hello hello', RegExp('(ll)(o)'), 'r'); | ||
expect(result).to.equal('hello herr'); | ||
}); | ||
it('contains regex chars', function() { | ||
var result = replaceLast('hello . hello . hello', /./, 'bye'); | ||
var result = replaceLast('hello . hello . hello', RegExp('.'), 'bye'); | ||
expect(result).to.equal('hello . hello . hellbye'); | ||
@@ -96,17 +174,61 @@ }); | ||
function resultsFromArgs(str, pattern, replacement) { | ||
return { | ||
result: replaceLast(str, pattern, replacement), | ||
lodashResult: _.replace(str, pattern, replacement) | ||
}; | ||
} | ||
it('str not a string', function() { | ||
var result = replaceLast({}, 'hello', 'bye'); | ||
expect(result).to.eql({}); | ||
var results = resultsFromArgs({}, 'hello', 'bye'); | ||
expect(results.result).to.equal('[object Object]'); | ||
expect(results.lodashResult).to.equal('[object Object]'); | ||
expect(results.result).to.equal(results.lodashResult); | ||
}); | ||
it('str undefined', function() { | ||
var results = resultsFromArgs(undefined, 'hello', 'bye'); | ||
expect(results.result).to.equal('undefined'); | ||
expect(results.lodashResult).to.equal(''); // inconsistent result, prefer 'undefined' | ||
}); | ||
it('pattern not a regex or string', function() { | ||
var result = replaceLast('hello hello', {}, 'bye'); | ||
expect(result).to.equal('hello hello'); | ||
var results = resultsFromArgs('hello hello', {}, 'bye'); | ||
expect(results.result).to.equal('hello hello'); | ||
expect(results.lodashResult).to.equal('hello hello'); | ||
expect(results.result).to.equal(results.lodashResult); | ||
}); | ||
it('pattern undefined', function() { | ||
var results = resultsFromArgs('hello hello', undefined, 'bye'); | ||
expect(results.result).to.equal('hello hello'); | ||
expect(results.lodashResult).to.equal('hello hello'); | ||
expect(results.result).to.equal(results.lodashResult); | ||
}); | ||
it('replacement not a string', function() { | ||
var result = replaceLast('hello hello', 'hello', {}); | ||
var results = resultsFromArgs('hello hello', 'hello', {}); | ||
expect(results.result).to.equal('hello [object Object]'); | ||
expect(results.lodashResult).to.equal('[object Object] hello'); | ||
}); | ||
it('replacement undefined', function() { | ||
var results = resultsFromArgs('hello hello', 'hello', undefined); | ||
// we use es5, lodash uses es6 | ||
// es6 can reliably determine the number of arguments passed in, es5 arguments.length is inconsistent across envs | ||
// in es5 it is safer to return the original string where "replacement" is undefined, | ||
// regardless as to whether it was literally passed in as undefined or just not given | ||
// thus this result is consistent with the replacement not given result below | ||
expect(results.result).to.equal('hello hello'); | ||
expect(results.lodashResult).to.equal('undefined hello'); | ||
}); | ||
it('replacement not given', function() { | ||
var result = replaceLast('hello hello', 'hello'); | ||
expect(result).to.equal('hello hello'); | ||
var lodashResult = _.replace('hello hello', 'hello'); | ||
expect(lodashResult).to.equal('hello hello'); | ||
expect(result).to.equal(lodashResult); | ||
}); | ||
}); | ||
}); |
{ | ||
"name": "replace-last", | ||
"version": "1.1.0", | ||
"description": "JavaScript replaceLast function", | ||
"version": "1.2.0", | ||
"description": "JavaScript replaceLast function - Replaces last match for pattern in string with replacement", | ||
"author": "danday74", | ||
@@ -23,3 +23,3 @@ "license": "ISC", | ||
"eslint": "^4.19.0", | ||
"gcf": "^0.0.2", | ||
"git-commit-file": "^1.3.1", | ||
"husky": "^0.14.3", | ||
@@ -33,4 +33,9 @@ "istanbul": "^0.4.5", | ||
"keywords": [ | ||
"replace last", | ||
"regex", | ||
"string", | ||
"replace", | ||
"last" | ||
"last", | ||
"lodash", | ||
"underscore" | ||
], | ||
@@ -37,0 +42,0 @@ "repository": { |
@@ -21,5 +21,5 @@ # replace-last | ||
`replace-last` supports String and Regex replacement. It works in Node code and browsers. | ||
`replace-last` supports string and RegExp replacement. It works in Node code and browsers. | ||
[View the code](js/replaceLast.js) | File size is 1.5 KB | Fully unit tested | ||
[View the code](js/replaceLast.js) | File size 1.7 KB | Fully unit tested | Zero dependency | ||
@@ -58,10 +58,16 @@ | ||
## Example | ||
## Examples | ||
```javascript 1.5 | ||
replaceLast('hello hello hello', 'hello', 'bye'); | ||
// => 'hello hello bye'; | ||
replaceLast('hello hello hello', /he(ll)o/, 'rr'); | ||
// => 'hello hello herro'; | ||
replaceLast('hello hello hello', RegExp('.ell.'), 'bye'); | ||
// => 'hello hello bye' | ||
replaceLast('hello hello hello', /hello/, 'bye'); | ||
// => 'hello hello bye' | ||
replaceLast(778, 8, 7); | ||
// => '777' | ||
``` | ||
@@ -75,4 +81,17 @@ | ||
BIBLE STUFF HERE :D | ||
God is the **last**? | ||
> "Behold, I (Jesus) am coming quickly, and My reward is with Me, to give to each one according to the merit of his deeds (earthly works, faithfulness). | ||
> I am the Alpha and the Omega, the First and the Last, the Beginning and the End [the Eternal One]." | ||
[REVELATION 22:12-13 AMP](https://www.bible.com/en-GB/bible/1588/REV.22.12-13.amp "Jesus loves you") | ||
Jesus, King of Kings (**first**) put himself **last** - paying the death penalty for your wrongdoing - by willingly dying on the cross for you in your place. | ||
He didn't do this because you loved Him. He did this even though you didn't love Him. He did this in the midst of all your hatred, your lust and worst of all, your apathy! | ||
The nails never held him there, His love for you did! He commands men everywhere to repent and offers forgiveness for all them that believe! | ||
<br><br><br> |
@@ -1,1 +0,1 @@ | ||
var replaceLast=function(t){var e={};function r(n){if(e[n])return e[n].exports;var o=e[n]={i:n,l:!1,exports:{}};return t[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}return r.m=t,r.c=e,r.d=function(t,e,n){r.o(t,e)||Object.defineProperty(t,e,{configurable:!1,enumerable:!0,get:n})},r.r=function(t){Object.defineProperty(t,"__esModule",{value:!0})},r.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return r.d(e,"a",e),e},r.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},r.p="",r(r.s=1)}([function(t,e,r){"use strict";t.exports=function(t,e,r){var n,o,u=t;if("number"==typeof t&&(t=t.toString()),"number"==typeof e&&(e=e.toString()),"number"==typeof r&&(r=r.toString()),"string"!=typeof t)return u;if("string"!=typeof r)return u;if("string"==typeof e)n=function(t,e,r){var n=t.lastIndexOf(e);return n<0?t:t.substring(0,n)+r+t.substring(n+e.length,t.length)}(t,e,r);else{if(o=e,"[object RegExp]"!==Object.prototype.toString.call(o))return u;n=function(t,e,r){return e=new RegExp(e.source,"g"),t.replace(e,function(t,n,o){return 1===o.slice(n).match(e).length?r:t})}(t,e,r)}return n===t?u:n}},function(t,e,r){"use strict";const n=r(0);t.exports=function(t,e,r){return n(t,e,r)}}]); | ||
var replaceLast=function(t){var e={};function r(n){if(e[n])return e[n].exports;var o=e[n]={i:n,l:!1,exports:{}};return t[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}return r.m=t,r.c=e,r.d=function(t,e,n){r.o(t,e)||Object.defineProperty(t,e,{configurable:!1,enumerable:!0,get:n})},r.r=function(t){Object.defineProperty(t,"__esModule",{value:!0})},r.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return r.d(e,"a",e),e},r.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},r.p="",r(r.s=1)}([function(t,e,r){"use strict";var n=function(t,e,r){var n=t.lastIndexOf(e);return n<0?t:t.substring(0,n)+r+t.substring(n+e.length,t.length)};t.exports=function(t,e,r){return t=""+t,void 0===r?t:(o=e,"[object RegExp]"===Object.prototype.toString.call(o)?function(t,e,r){void 0===RegExp.prototype.flags&&Object.defineProperty(RegExp.prototype,"flags",{configurable:!0,get:function(){return this.toString().match(/[gimuy]*$/)[0]}});var o=-1===e.flags.indexOf("g")?e.flags+"g":e.flags;return e=new RegExp(e.source,o),t.replace(e,function(){var t=arguments[0],o=Array.prototype.slice.call(arguments,1,arguments.length-2),u=arguments[arguments.length-2];if(1!==arguments[arguments.length-1].slice(u).match(e).length)return t;if(!o.length)return r;for(var c=0;c<o.length;c++)t=n(t,o[c],r);return t})}(t,e,r):n(t,e=""+e,r));var o}},function(t,e,r){"use strict";const n=r(0);t.exports=function(t,e,r){return n(t,e,r)}}]); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
18539
18
254
95
1