Skip to content

Commit 01313f9

Browse files
author
Bart Veneman
committed
Add option to get collection item locations
1 parent e5b0e68 commit 01313f9

File tree

5 files changed

+115
-45
lines changed

5 files changed

+115
-45
lines changed

src/collection.js

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,28 @@
11
export class Collection {
2-
constructor() {
2+
constructor({ useLocations = false }) {
33
/** @type {Map<string, Array<Number>>} */
44
this._items = new Map()
55
this._total = 0
6+
/** @type {number[]} */
67
this.node_lines = []
8+
/** @type {number[]} */
79
this.node_columns = []
10+
/** @type {number[]} */
811
this.node_lenghts = []
12+
/** @type {number[]} */
913
this.node_offsets = []
14+
15+
/** @type {boolean} */
16+
this.useLocations = useLocations
1017
}
1118

1219
/**
1320
* @param {string} item
1421
* @param {import('css-tree').CssLocation} node_location
1522
*/
1623
push(item, node_location) {
17-
let index = this._totalq
24+
let index = this._total
25+
1826
this.node_lines[index] = node_location.start.line
1927
this.node_columns[index] = node_location.start.column
2028
this.node_offsets[index] = node_location.start.offset
@@ -24,7 +32,6 @@ export class Collection {
2432
/** @type number[] */
2533
let list = this._items.get(item)
2634
list.push(index)
27-
// this._items.set(item, list)
2835
this._total++
2936
return
3037
}
@@ -38,7 +45,7 @@ export class Collection {
3845
}
3946

4047
count() {
41-
let items = new Map()
48+
let uniqueWithLocations = new Map()
4249
let unique = {}
4350
this._items.forEach((list, key) => {
4451
let nodes = list.map(index => ({
@@ -47,17 +54,27 @@ export class Collection {
4754
offset: this.node_offsets[index],
4855
length: this.node_lenghts[index],
4956
}))
50-
items.set(key, nodes)
57+
uniqueWithLocations.set(key, nodes)
5158
unique[key] = list.length
5259
})
5360

61+
if (this.useLocations) {
62+
return {
63+
total: this._total,
64+
totalUnique: this._items.size,
65+
unique: Object.fromEntries(this._items),
66+
unique,
67+
uniquenessRatio: this._total === 0 ? 0 : this._items.size / this._total,
68+
__unstable__uniqueWithLocations: Object.fromEntries(uniqueWithLocations),
69+
}
70+
}
71+
5472
return {
5573
total: this._total,
5674
totalUnique: this._items.size,
57-
// unique: Object.fromEntries(this._items),
75+
unique: Object.fromEntries(this._items),
5876
unique,
5977
uniquenessRatio: this._total === 0 ? 0 : this._items.size / this._total,
60-
// __unstable__itemsWithLocations: Object.fromEntries(items),
6178
}
6279
}
6380
}

src/context-collection.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
import { Collection } from './collection.js'
22

33
class ContextCollection {
4-
constructor() {
5-
this._list = new Collection()
4+
constructor({ useLocations = false }) {
5+
this._list = new Collection({ useLocations })
66
/** @type {Map<string, Collection>} */
77
this._contexts = new Map()
8+
/** @type {boolean} */
9+
this.useLocations = useLocations
810
}
911

1012
/**
@@ -17,7 +19,7 @@ class ContextCollection {
1719
this._list.push(item, node_location)
1820

1921
if (!this._contexts.has(context)) {
20-
this._contexts.set(context, new Collection())
22+
this._contexts.set(context, new Collection({ useLocations: this.useLocations }))
2123
}
2224

2325
this._contexts.get(context).push(item, node_location)

src/index.js

Lines changed: 39 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,17 @@ function ratio(part, total) {
2525
return part / total
2626
}
2727

28+
let defaults = {
29+
useUnstableLocations: false
30+
}
31+
2832
/**
2933
* Analyze CSS
3034
* @param {string} css
3135
*/
32-
function analyze(css) {
36+
function analyze(css, options = {}) {
37+
let settings = Object.assign({}, defaults, options)
38+
let useLocations = settings.useUnstableLocations === true
3339
let start = Date.now()
3440

3541
/**
@@ -75,16 +81,16 @@ function analyze(css) {
7581
let totalAtRules = 0
7682
/** @type {{[property: string]: string}[]} */
7783
let fontfaces = []
78-
let layers = new Collection()
79-
let imports = new Collection()
80-
let medias = new Collection()
81-
let mediaBrowserhacks = new Collection()
82-
let charsets = new Collection()
83-
let supports = new Collection()
84-
let supportsBrowserhacks = new Collection()
85-
let keyframes = new Collection()
86-
let prefixedKeyframes = new Collection()
87-
let containers = new Collection()
84+
let layers = new Collection({ useLocations })
85+
let imports = new Collection({ useLocations })
86+
let medias = new Collection({ useLocations })
87+
let mediaBrowserhacks = new Collection({ useLocations })
88+
let charsets = new Collection({ useLocations })
89+
let supports = new Collection({ useLocations })
90+
let supportsBrowserhacks = new Collection({ useLocations })
91+
let keyframes = new Collection({ useLocations })
92+
let prefixedKeyframes = new Collection({ useLocations })
93+
let containers = new Collection({ useLocations })
8894

8995
// Rules
9096
let totalRules = 0
@@ -94,9 +100,9 @@ function analyze(css) {
94100
let declarationsPerRule = new AggregateCollection()
95101

96102
// Selectors
97-
let keyframeSelectors = new Collection()
103+
let keyframeSelectors = new Collection({ useLocations })
98104
let uniqueSelectors = new Set()
99-
let prefixedSelectors = new Collection()
105+
let prefixedSelectors = new Collection({ useLocations })
100106
/** @type {Specificity} */
101107
let maxSpecificity
102108
/** @type {Specificity} */
@@ -108,35 +114,35 @@ function analyze(css) {
108114
let selectorComplexities = new AggregateCollection()
109115
/** @type {Specificity[]} */
110116
let specificities = []
111-
let ids = new Collection()
112-
let a11y = new Collection()
117+
let ids = new Collection({ useLocations })
118+
let a11y = new Collection({ useLocations })
113119

114120
// Declarations
115121
let uniqueDeclarations = new Set()
116122
let totalDeclarations = 0
117123
let importantDeclarations = 0
118124
let importantsInKeyframes = 0
119-
let importantCustomProperties = new Collection()
125+
let importantCustomProperties = new Collection({ useLocations })
120126

121127
// Properties
122-
let properties = new Collection()
123-
let propertyHacks = new Collection()
124-
let propertyVendorPrefixes = new Collection()
125-
let customProperties = new Collection()
128+
let properties = new Collection({ useLocations })
129+
let propertyHacks = new Collection({ useLocations })
130+
let propertyVendorPrefixes = new Collection({ useLocations })
131+
let customProperties = new Collection({ useLocations })
126132
let propertyComplexities = new AggregateCollection()
127133

128134
// Values
129-
let vendorPrefixedValues = new Collection()
130-
let valueBrowserhacks = new Collection()
131-
let zindex = new Collection()
132-
let textShadows = new Collection()
133-
let boxShadows = new Collection()
134-
let fontFamilies = new Collection()
135-
let fontSizes = new Collection()
136-
let lineHeights = new Collection()
137-
let timingFunctions = new Collection()
138-
let durations = new Collection()
139-
let colors = new ContextCollection()
135+
let vendorPrefixedValues = new Collection({ useLocations })
136+
let valueBrowserhacks = new Collection({ useLocations })
137+
let zindex = new Collection({ useLocations })
138+
let textShadows = new Collection({ useLocations })
139+
let boxShadows = new Collection({ useLocations })
140+
let fontFamilies = new Collection({ useLocations })
141+
let fontSizes = new Collection({ useLocations })
142+
let lineHeights = new Collection({ useLocations })
143+
let timingFunctions = new Collection({ useLocations })
144+
let durations = new Collection({ useLocations })
145+
let colors = new ContextCollection({ useLocations })
140146
let colorFormats = new CountableCollection()
141147
let units = new ContextCollection()
142148
let gradients = new CountableCollection()
@@ -364,12 +370,12 @@ function analyze(css) {
364370

365371
break
366372
} else if (isProperty('font-size', property)) {
367-
if (!isFontKeyword(node)) {
373+
if (!isSystemFont(node)) {
368374
fontSizes.push(stringifyNode(node), node.loc)
369375
}
370376
break
371377
} else if (isProperty('font-family', property)) {
372-
if (!isFontKeyword(node)) {
378+
if (!isSystemFont(node)) {
373379
fontFamilies.push(stringifyNode(node), node.loc)
374380
}
375381
break

src/values/colors.test.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1051,4 +1051,49 @@ Colors('insane color mode', () => {
10511051
assert.not.throws(() => analyze(fixture))
10521052
})
10531053

1054+
Colors('Lists locations when unstable flag is set', () => {
1055+
let css = `
1056+
thing {
1057+
color: red;
1058+
color: #f00;
1059+
color: rgb(255, 0, 0);
1060+
background-color: red;
1061+
}
1062+
`
1063+
let actual = analyze(css, { useUnstableLocations: true })
1064+
1065+
assert.equal(actual.values.colors.__unstable__uniqueWithLocations, {
1066+
'red': [
1067+
{
1068+
line: 3,
1069+
column: 14,
1070+
offset: 26,
1071+
length: 3,
1072+
},
1073+
{
1074+
line: 6,
1075+
column: 25,
1076+
offset: 103,
1077+
length: 3,
1078+
}
1079+
],
1080+
'#f00': [
1081+
{
1082+
line: 4,
1083+
column: 14,
1084+
offset: 44,
1085+
length: 4,
1086+
}
1087+
],
1088+
'rgb(255, 0, 0)': [
1089+
{
1090+
line: 5,
1091+
column: 14,
1092+
offset: 63,
1093+
length: 14,
1094+
}
1095+
]
1096+
})
1097+
})
1098+
10541099
Colors.run()

src/values/vendor-prefix.test.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ VendorPrefix('finds simple prefixes', () => {
3131
`
3232
const actual = analyze(fixture).values.prefixes
3333
const expected = {
34-
total: 8,
34+
total: 9,
3535
totalUnique: 7,
3636
unique: {
3737
'-moz-max-content': 1,
@@ -42,7 +42,7 @@ VendorPrefix('finds simple prefixes', () => {
4242
'-moz-transform 0.3s ease-out': 1,
4343
'-o-transform 0.3s ease-out': 2,
4444
},
45-
uniquenessRatio: 7 / 8
45+
uniquenessRatio: 7 / 9,
4646
}
4747

4848
assert.equal(actual, expected)

0 commit comments

Comments
 (0)