Skip to content

Commit 28d1f4e

Browse files
author
Bart Veneman
committed
types
1 parent b131d84 commit 28d1f4e

File tree

4 files changed

+39
-13
lines changed

4 files changed

+39
-13
lines changed

package-lock.json

Lines changed: 15 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
"devDependencies": {
5656
"@codecov/vite-plugin": "^0.0.1-beta.8",
5757
"@codspeed/tinybench-plugin": "^3.1.0",
58+
"@types/css-tree": "^2.3.8",
5859
"c8": "^9.1.0",
5960
"tinybench": "^2.8.0",
6061
"uvu": "^0.5.6",
@@ -64,4 +65,4 @@
6465
"mangle": {
6566
"regex": "^_[^_]"
6667
}
67-
}
68+
}

src/collection.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,13 @@ export class Collection {
1515
}
1616

1717
/**
18-
* @param {string} item
19-
* @param {import('css-tree').CssLocation} node_location
18+
* @param {string | number} item
19+
* @param {import('css-tree').CssLocation | undefined} node_location
2020
*/
2121
p(item, node_location) {
2222
let index = this._total
2323

24-
if (this._useLocations) {
24+
if (this._useLocations && node_location) {
2525
let start = node_location.start
2626
let start_offset = start.offset
2727
let position = index * 4

src/index.js

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1+
// @ts-expect-error No types for sub-export `parse` and `walk`
12
import parse from 'css-tree/parser'
3+
// @ts-expect-error No types for sub-export `parse` and `walk`
24
import walk from 'css-tree/walker'
5+
// @ts-expect-error No types for sub-export `core`
36
import { calculate } from '@bramus/specificity/core'
47
import { isSupportsBrowserhack, isMediaBrowserhack } from './atrules/atrules.js'
58
import { getCombinators, getComplexity, isAccessibility, isPrefixed } from './selectors/utils.js'
@@ -46,6 +49,12 @@ let border_radius_properties = new KeywordSet([
4649
'border-end-start-radius',
4750
])
4851

52+
/**
53+
* Safe ratio calculation to avoid division by zero errors
54+
* @param {number} part
55+
* @param {number} total
56+
* @returns {number}
57+
*/
4958
function ratio(part, total) {
5059
if (total === 0) return 0
5160
return part / total
@@ -79,7 +88,9 @@ export function analyze(css, options = {}) {
7988
return stringifyNodePlain(node).trim()
8089
}
8190

91+
/** @param {import('css-tree').CssNode} node */
8292
function stringifyNodePlain(node) {
93+
/** @type {import('css-tree').CssNode as NonNullable<import('css-tree').CssNode['loc']>} */
8394
let loc = node.loc
8495
return css.substring(loc.start.offset, loc.end.offset)
8596
}
@@ -192,7 +203,7 @@ export function analyze(css, options = {}) {
192203
let valueKeywords = new Collection(useLocations)
193204
let borderRadiuses = new ContextCollection(useLocations)
194205

195-
walk(ast, function (node) {
206+
walk(ast, function (/** @type {import('css-tree').CssNode} */node) {
196207
switch (node.type) {
197208
case Atrule: {
198209
totalAtRules++
@@ -203,10 +214,10 @@ export function analyze(css, options = {}) {
203214
let descriptors = {}
204215

205216
if (useLocations) {
206-
fontfaces_with_loc.p(node.loc.start.offset, node.loc)
217+
fontfaces_with_loc.p(node.loc?.start.offset, node.loc)
207218
}
208219

209-
node.block.children.forEach(descriptor => {
220+
node.block?.children.forEach(descriptor => {
210221
// Ignore 'Raw' nodes in case of CSS syntax errors
211222
if (descriptor.type === Declaration) {
212223
descriptors[descriptor.property] = stringifyNode(descriptor.value)
@@ -228,15 +239,15 @@ export function analyze(css, options = {}) {
228239

229240
if (atRuleName === 'media') {
230241
medias.p(preludeStr, loc)
231-
if (isMediaBrowserhack(prelude)) {
242+
if (prelude.type === 'AtrulePrelude' && isMediaBrowserhack(prelude)) {
232243
mediaBrowserhacks.p(preludeStr, loc)
233244
complexity++
234245
}
235246
} else if (atRuleName === 'supports') {
236247
supports.p(preludeStr, loc)
237248
// TODO: analyze vendor prefixes in @supports
238249
// TODO: analyze complexity of @supports 'declaration'
239-
if (isSupportsBrowserhack(prelude)) {
250+
if (prelude.type === 'AtrulePrelude' && isSupportsBrowserhack(prelude)) {
240251
supportsBrowserhacks.p(preludeStr, loc)
241252
complexity++
242253
}
@@ -276,7 +287,7 @@ export function analyze(css, options = {}) {
276287
case Rule: {
277288
let prelude = node.prelude
278289
let block = node.block
279-
let preludeChildren = prelude.children
290+
let preludeChildren = prelude.type === 'SelectorList' ? prelude.children : new Set()
280291
let blockChildren = block.children
281292
let numSelectors = preludeChildren ? preludeChildren.size : 0
282293
let numDeclarations = blockChildren ? blockChildren.size : 0
@@ -355,7 +366,7 @@ export function analyze(css, options = {}) {
355366
ids.p(selector, node.loc)
356367
}
357368

358-
getCombinators(node, function onCombinator(combinator) {
369+
getCombinators(node, function onCombinator(/** @type {import('css-tree').Combinator} */ combinator) {
359370
combinators.p(combinator.name, combinator.loc)
360371
})
361372

@@ -546,7 +557,7 @@ export function analyze(css, options = {}) {
546557
// no break here: potentially contains colors
547558
}
548559

549-
walk(node, function (valueNode) {
560+
walk(node, function (/** @type {import('css-tree').CssNode} */ valueNode) {
550561
let nodeName = valueNode.name
551562

552563
switch (valueNode.type) {

0 commit comments

Comments
 (0)