-
-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
439 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,184 @@ | ||
import rcs from '../../lib'; | ||
|
||
beforeEach(() => { | ||
rcs.cssVariablesLibrary.setAlphabet('#abcdefghijklmnopqrstuvwxyz'); | ||
rcs.cssVariablesLibrary.reset(); | ||
rcs.keyframesLibrary.setAlphabet('#abcdefghijklmnopqrstuvwxyz'); | ||
rcs.keyframesLibrary.reset(); | ||
rcs.selectorsLibrary.setAlphabet('#abcdefghijklmnopqrstuvwxyz'); | ||
rcs.selectorsLibrary.reset(); | ||
}); | ||
|
||
test('should ignore everything without selectors', () => { | ||
const input = { }; | ||
|
||
rcs.mapping.load(input); | ||
rcs.optimize(); | ||
|
||
expect(rcs.mapping.generate()).toEqual(input); | ||
}); | ||
|
||
test('should ignore when no statistics are available', () => { | ||
const input = { | ||
selectors: { | ||
'#test': 'a', | ||
'.ca': 'a', | ||
'.ba': 'b', | ||
'.aa': 'c', | ||
}, | ||
}; | ||
|
||
rcs.mapping.load(input); | ||
rcs.optimize(); | ||
|
||
expect(rcs.mapping.generate()).toEqual(input); | ||
}); | ||
|
||
test('should optimize without usageCount', () => { | ||
rcs.mapping.load({ | ||
selectors: { | ||
'#test': 'a', | ||
'.ca': 'a', | ||
'.ba': 'b', | ||
'.aa': 'c', | ||
}, | ||
}); | ||
rcs.statistics.load({ | ||
ids: { | ||
unused: [], | ||
usageCount: { | ||
test: 2, | ||
}, | ||
}, | ||
classes: { | ||
unused: [], | ||
usageCount: { | ||
'my-selector': 2, | ||
}, | ||
}, | ||
keyframes: { | ||
unused: [], | ||
usageCount: {}, | ||
}, | ||
cssVariables: { | ||
unused: [], | ||
usageCount: {}, | ||
}, | ||
}); | ||
|
||
rcs.optimize(); | ||
|
||
expect(rcs.mapping.generate()).toEqual({ | ||
selectors: { | ||
'#test': 'a', | ||
'.aa': 'c', | ||
'.ba': 'b', | ||
'.ca': 'a', | ||
}, | ||
}); | ||
}); | ||
|
||
test('should optimize with usageCount', () => { | ||
rcs.mapping.load({ | ||
selectors: { | ||
'#test': 'a', | ||
'.ca': 'a', | ||
'.ba': 'b', | ||
'.aa': 'c', | ||
}, | ||
}); | ||
rcs.statistics.load({ | ||
ids: { | ||
unused: [], | ||
usageCount: { | ||
test: 2, | ||
}, | ||
}, | ||
classes: { | ||
unused: [], | ||
usageCount: { | ||
ca: 3, | ||
ba: 10, | ||
}, | ||
}, | ||
keyframes: { | ||
unused: [], | ||
usageCount: {}, | ||
}, | ||
cssVariables: { | ||
unused: [], | ||
usageCount: {}, | ||
}, | ||
}); | ||
|
||
rcs.optimize(); | ||
|
||
expect(rcs.mapping.generate()).toEqual({ | ||
selectors: { | ||
'#test': 'a', | ||
'.aa': 'c', | ||
'.ba': 'a', | ||
'.ca': 'b', | ||
}, | ||
}); | ||
}); | ||
|
||
test('should optimize everything', () => { | ||
rcs.mapping.load({ | ||
selectors: { | ||
'#a-first': 'a', | ||
'#b-second': 'b', | ||
'.a-first': 'a', | ||
'.b-second': 'b', | ||
'@a-first': 'a', | ||
'@b-second': 'b', | ||
'-a-first': 'a', | ||
'-b-second': 'b', | ||
}, | ||
}); | ||
rcs.statistics.load({ | ||
ids: { | ||
unused: [], | ||
usageCount: { | ||
'a-first': 1, | ||
'b-second': 3, | ||
}, | ||
}, | ||
classes: { | ||
unused: [], | ||
usageCount: { | ||
'a-first': 1, | ||
'b-second': 3, | ||
}, | ||
}, | ||
keyframes: { | ||
unused: [], | ||
usageCount: { | ||
'a-first': 1, | ||
'b-second': 3, | ||
}, | ||
}, | ||
cssVariables: { | ||
unused: [], | ||
usageCount: { | ||
'a-first': 1, | ||
'b-second': 3, | ||
}, | ||
}, | ||
}); | ||
|
||
rcs.optimize(); | ||
|
||
expect(rcs.mapping.generate()).toEqual({ | ||
selectors: { | ||
'#a-first': 'b', | ||
'#b-second': 'a', | ||
'.a-first': 'b', | ||
'.b-second': 'a', | ||
'@a-first': 'b', | ||
'@b-second': 'a', | ||
'-a-first': 'b', | ||
'-b-second': 'a', | ||
}, | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import separateMappingSelectors from '../../lib/optimize/separateMappingSelectors'; | ||
|
||
test('should do nothing', () => { | ||
expect(separateMappingSelectors()).toEqual({ | ||
cssVariables: [], | ||
keyframes: [], | ||
classes: [], | ||
ids: [], | ||
}); | ||
}); | ||
|
||
test('should separate selectors correctly', () => { | ||
expect(separateMappingSelectors({ | ||
'.test': 'a', | ||
'#my-id': 'a', | ||
'#my-other-id': 'b', | ||
})).toEqual({ | ||
cssVariables: [], | ||
keyframes: [], | ||
classes: [['test', 'a']], | ||
ids: [['my-id', 'a'], ['my-other-id', 'b']], | ||
}); | ||
}); | ||
|
||
test('should separate selectors, keyframes and cssVariables correctly', () => { | ||
expect(separateMappingSelectors({ | ||
'.test': 'a', | ||
'#my-id': 'a', | ||
'#my-other-id': 'b', | ||
'-my-var': 'a', | ||
'@my-keyframe': 'a', | ||
})).toEqual({ | ||
cssVariables: [['my-var', 'a']], | ||
keyframes: [['my-keyframe', 'a']], | ||
classes: [['test', 'a']], | ||
ids: [['my-id', 'a'], ['my-other-id', 'b']], | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
import sortSelectors from '../../lib/optimize/sortSelectors'; | ||
|
||
test('should ignore usage count for sorting', () => { | ||
const result = sortSelectors( | ||
['my-selector', 'should-be-here'], | ||
{ | ||
unused: [], | ||
usageCount: { | ||
'not-available-selector': 14, | ||
'my-selector': 2, | ||
}, | ||
}, | ||
); | ||
|
||
expect(result).toEqual(['my-selector', 'should-be-here']); | ||
}); | ||
|
||
test('should optimize', () => { | ||
const result = sortSelectors( | ||
['short-selector', 'a-very-long-selector'], | ||
{ | ||
unused: [], | ||
usageCount: { | ||
'short-selector': 14, | ||
'a-very-long-selector': 2, | ||
}, | ||
}, | ||
); | ||
|
||
expect(result).toEqual(['short-selector', 'a-very-long-selector']); | ||
}); | ||
|
||
test('sort by occurrence count', () => { | ||
const result = sortSelectors( | ||
['short-selector', 'a-very-long-selector'], | ||
{ | ||
unused: [], | ||
usageCount: { | ||
'short-selector': 2, | ||
'a-very-long-selector': 14, | ||
}, | ||
}, | ||
); | ||
|
||
expect(result).toEqual(['a-very-long-selector', 'short-selector']); | ||
}); | ||
|
||
test('should sort three by occurrence coun', () => { | ||
const result = sortSelectors( | ||
['first-id', 'second-id', 'third-id'], | ||
{ | ||
unused: [], | ||
usageCount: { | ||
'first-id': 25, | ||
'second-id': 32, | ||
'third-id': 29, | ||
}, | ||
}, | ||
); | ||
|
||
expect(result).toEqual(['second-id', 'third-id', 'first-id']); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
import optimize from './optimize'; | ||
|
||
export default optimize; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
import generateMapping from '../mapping/generate'; | ||
import generateStatistics from '../statistics/generate'; | ||
import { getStatistics } from '../statistics'; | ||
import loadMapping from '../mapping/load'; | ||
import selectorsLibrary from '../selectorsLibrary'; | ||
import keyframesLibrary from '../keyframesLibrary'; | ||
import cssVariablesLibrary from '../cssVariablesLibrary'; | ||
import separateMappingSelectors from './separateMappingSelectors'; | ||
import sortSelectors from './sortSelectors'; | ||
|
||
const optimize = (): void => { | ||
const mapping = generateMapping(); | ||
const statistics = getStatistics(); | ||
|
||
if (!statistics) { | ||
return; | ||
} | ||
|
||
// sorting | ||
// renaming into new mapping | ||
const separateMapping = separateMappingSelectors(mapping.selectors); | ||
const optimizedMapping: { [key in keyof ReturnType<typeof generateStatistics>]?: string[] } = {}; | ||
|
||
// optimize each library | ||
Object.entries(separateMapping).forEach(([key, selectors]) => { | ||
const statisticsData = statistics[key as 'ids']; | ||
const newSortedSelectors = sortSelectors(selectors.map(([s]) => s), statisticsData); | ||
|
||
optimizedMapping[key as 'ids'] = newSortedSelectors; | ||
}); | ||
|
||
// could be a cold start but | ||
// reset everything just in case | ||
selectorsLibrary.reset(); | ||
keyframesLibrary.reset(); | ||
cssVariablesLibrary.reset(); | ||
|
||
// fill libraries with optimized mapping | ||
Object.entries(optimizedMapping).forEach(([key, selectors]) => { | ||
if (!selectors) { | ||
return; | ||
} | ||
|
||
switch (key) { | ||
case 'ids': | ||
selectors.forEach((selector) => selectorsLibrary.set(`#${selector}`)); | ||
|
||
break; | ||
|
||
case 'keyframes': | ||
selectors.forEach((selector) => keyframesLibrary.set(`@${selector}`)); | ||
|
||
break; | ||
|
||
case 'cssVariables': | ||
selectors.forEach((selector) => cssVariablesLibrary.set(`--${selector}`)); | ||
|
||
break; | ||
|
||
case 'classes': | ||
default: | ||
selectors.forEach((selector) => selectorsLibrary.set(`.${selector}`)); | ||
} | ||
}); | ||
|
||
// load with the same attribute selectors | ||
// these cannot be optimized yet | ||
loadMapping({ attributeSelectors: mapping.attributeSelectors }); | ||
}; | ||
|
||
export default optimize; |
Oops, something went wrong.