From d49fb5ca8eb7a013924a515a02d34a4e0b36ee0f Mon Sep 17 00:00:00 2001 From: Georgios Kalpakas Date: Wed, 6 Jan 2016 17:04:29 +0200 Subject: [PATCH] fix(linky): throw error if input is not a string BREAKING CHANGE: Before this change, the filter assumed that the input (if not undefined/null) was of type 'string' and that certain methods (such as `.match()`) would be available on it. Passing a non-string value would most likely result in a not-very-useful error being thrown (trying to call a method that does not exist) or in unexpected behavior (if the input happened to have the assumed methods). After this change, a proper (informative) error will be thrown. If you want to pass non-string values through `linky`, you need to explicitly convert them to strings first. Since input values could be initialized asynchronously, `undefined` or `null` will still be returned unchanged (without throwing an error). Closes #13547 --- docs/content/error/linky/notstring.ngdoc | 16 ++++++++++++ src/ngSanitize/filter/linky.js | 7 +++++- test/ngSanitize/filter/linkySpec.js | 31 ++++++++++++++++++++++++ 3 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 docs/content/error/linky/notstring.ngdoc diff --git a/docs/content/error/linky/notstring.ngdoc b/docs/content/error/linky/notstring.ngdoc new file mode 100644 index 000000000000..159ac42de123 --- /dev/null +++ b/docs/content/error/linky/notstring.ngdoc @@ -0,0 +1,16 @@ +@ngdoc error +@name linky:notstring +@fullName Not a string +@description + +This error occurs when {@link ngSanitize.linky linky} is used with a non-empty, non-string value: +```html +
+``` + +`linky` is supposed to be used with string values only, and therefore assumes that several methods +(such as `.match()`) are available on the passed in value. +The value can be initialized asynchronously and therefore null or undefined won't throw this error. + +If you want to pass non-string values to `linky` (e.g. Objects whose `.toString()` should be +utilized), you need to manually convert them to strings. diff --git a/src/ngSanitize/filter/linky.js b/src/ngSanitize/filter/linky.js index 2780d74c0b33..495dd80af7ab 100644 --- a/src/ngSanitize/filter/linky.js +++ b/src/ngSanitize/filter/linky.js @@ -134,8 +134,13 @@ angular.module('ngSanitize').filter('linky', ['$sanitize', function($sanitize) { /((ftp|https?):\/\/|(www\.)|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s.;,(){}<>"\u201d\u2019]/i, MAILTO_REGEXP = /^mailto:/i; + var linkyMinErr = angular.$$minErr('linky'); + var isString = angular.isString; + return function(text, target, attributes) { - if (!text) return text; + if (text == null || text === '') return text; + if (!isString(text)) throw linkyMinErr('notstring', 'Expected string but received: {0}', text); + var match; var raw = text; var html = []; diff --git a/test/ngSanitize/filter/linkySpec.js b/test/ngSanitize/filter/linkySpec.js index a3dafb18ddce..5077ae9bf406 100644 --- a/test/ngSanitize/filter/linkySpec.js +++ b/test/ngSanitize/filter/linkySpec.js @@ -20,6 +20,37 @@ describe('linky', function() { expect(linky(undefined)).not.toBeDefined(); }); + it('should return `undefined`/`null`/`""` values unchanged', function() { + expect(linky(undefined)).toBe(undefined); + expect(linky(null)).toBe(null); + expect(linky('')).toBe(''); + }); + + it('should throw an error when used with a non-string value (other than `undefined`/`null`)', + function() { + expect(function() { linky(false); }). + toThrowMinErr('linky', 'notstring', 'Expected string but received: false'); + + expect(function() { linky(true); }). + toThrowMinErr('linky', 'notstring', 'Expected string but received: true'); + + expect(function() { linky(0); }). + toThrowMinErr('linky', 'notstring', 'Expected string but received: 0'); + + expect(function() { linky(42); }). + toThrowMinErr('linky', 'notstring', 'Expected string but received: 42'); + + expect(function() { linky({}); }). + toThrowMinErr('linky', 'notstring', 'Expected string but received: {}'); + + expect(function() { linky([]); }). + toThrowMinErr('linky', 'notstring', 'Expected string but received: []'); + + expect(function() { linky(noop); }). + toThrowMinErr('linky', 'notstring', 'Expected string but received: function noop()'); + } + ); + it('should be case-insensitive', function() { expect(linky('WWW.example.com')).toEqual('WWW.example.com'); expect(linky('WWW.EXAMPLE.COM')).toEqual('WWW.EXAMPLE.COM');