From ab9f0760a07eeaab510686d58123088fe737dfd7 Mon Sep 17 00:00:00 2001 From: Vincent Wochnik Date: Mon, 20 Feb 2017 10:20:02 +0100 Subject: [PATCH] fix: Limits the number of class-combinations to avoid freeze (#23) * Limits the number of class-combinations to avoid freeze * add test * add jsdoc --- src/getCombinations.js | 44 +++++++++++++++++++++++++++++++++++++++++ src/index.js | 28 ++------------------------ test/unique-selector.js | 9 +++++++++ 3 files changed, 55 insertions(+), 26 deletions(-) create mode 100644 src/getCombinations.js diff --git a/src/getCombinations.js b/src/getCombinations.js new file mode 100644 index 0000000..abfdba6 --- /dev/null +++ b/src/getCombinations.js @@ -0,0 +1,44 @@ +/** + * Recursively combinate items. + * @param { Array } result + * @param { Array } items + * @param { Array } data + * @param { Number } start + * @param { Number } end + * @param { Number } index + * @param { Number } k + */ +function kCombinations( result, items, data, start, end, index, k ) +{ + if( index === k ) + { + result.push( data.slice( 0, index ).join( '' ) ); + return; + } + + for( let i = start; i <= end && end - i + 1 >= k - index; ++i ) + { + data[index] = items[i]; + kCombinations( result, items, data, i + 1, end, index + 1, k ); + } +} + +/** + * Returns all the possible selector combinations + * @param { Array } items + * @param { Number } k + * @return { Array } + */ +export function getCombinations( items, k ) +{ + const result = [], + n = items.length, + data = []; + + for( var l = 1; l <= k; ++l ) + { + kCombinations( result, items, data, 0, n - 1, 0, l ); + } + + return result; +} diff --git a/src/index.js b/src/index.js index 9b5d7b0..7a899a6 100644 --- a/src/index.js +++ b/src/index.js @@ -4,6 +4,7 @@ import { getID } from './getID'; import { getClassSelectors } from './getClasses'; +import { getCombinations } from './getCombinations'; import { getAttributes } from './getAttributes'; import { getNthChild } from './getNthChild'; import { getTag } from './getTag'; @@ -56,7 +57,7 @@ function testUniqueness( element, selector ) */ function getUniqueCombination( element, items, tag ) { - const combinations = getCombinations( items ); + const combinations = getCombinations( items, 3 ); const uniqCombinations = combinations.filter( testUniqueness.bind( this, element ) ); if( uniqCombinations.length ) return uniqCombinations[ 0 ]; @@ -132,31 +133,6 @@ function getUniqueSelector( element, selectorTypes, attributesToIgnore ) return '*'; } -/** - * Returns all the possible selector combinations - */ -function getCombinations( items ) -{ - items = items ? items : []; - let result = [[]]; - let i, j, k, l, ref, ref1; - - for ( i = k = 0, ref = items.length - 1; 0 <= ref ? k <= ref : k >= ref; i = 0 <= ref ? ++k : --k ) - { - for ( j = l = 0, ref1 = result.length - 1; 0 <= ref1 ? l <= ref1 : l >= ref1; j = 0 <= ref1 ? ++l : --l ) - { - result.push( result[ j ].concat( items[ i ] ) ); - } - } - - result.shift(); - result = result.sort( ( a, b ) => a.length - b.length ); - result = result.map( item => item.join( '' ) ); - - return result; -} - - /** * Generate unique CSS selector for given DOM element * diff --git a/test/unique-selector.js b/test/unique-selector.js index 285685c..b461c02 100644 --- a/test/unique-selector.js +++ b/test/unique-selector.js @@ -35,6 +35,15 @@ describe( 'Unique Selector Tests', () => expect( uniqueSelector ).to.equal( 'body > :nth-child(1)' ); } ); + it( 'Classes', () => + { + $( 'body' ).get( 0 ).innerHTML = ''; //Clear previous appends + $( 'body' ).append( '
' ); + const findNode = $( 'body' ).find( '.test2' ).get( 0 ); + const uniqueSelector = unique( findNode ); + expect( uniqueSelector ).to.equal( '.cc.cx' ); + } ); + it( 'Tag', () => {