Skip to content

Commit f56875c

Browse files
committed
it works now!!!
1 parent 47bb65d commit f56875c

File tree

10 files changed

+631
-322
lines changed

10 files changed

+631
-322
lines changed

src/lib/chunkify.test.ts

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
import { test, expect } from '@playwright/test'
2+
import { chunkify, type ChunkedCoverage } from './chunkify'
3+
4+
test('creates chunks with outer chunks covered', () => {
5+
let coverage = {
6+
text: 'a { color: red; } b { color: green; } c { color: blue; }',
7+
ranges: [
8+
{ start: 0, end: 17 },
9+
{ start: 38, end: 56 },
10+
],
11+
url: 'https://example.com',
12+
}
13+
let result = chunkify(coverage)
14+
delete coverage.ranges
15+
expect(result).toEqual({
16+
...coverage,
17+
chunks: [
18+
{
19+
start_offset: 0,
20+
end_offset: 17,
21+
is_covered: true,
22+
},
23+
{
24+
start_offset: 17,
25+
end_offset: 38,
26+
is_covered: false,
27+
},
28+
{
29+
start_offset: 38,
30+
end_offset: 56,
31+
is_covered: true,
32+
},
33+
],
34+
} satisfies ChunkedCoverage)
35+
})
36+
37+
test('creates chunks with only middle chunk covered', () => {
38+
let coverage = {
39+
text: 'a { color: red; } b { color: green; } c { color: blue; }',
40+
ranges: [{ start: 17, end: 38 }],
41+
url: 'https://example.com',
42+
}
43+
let result = chunkify(coverage)
44+
delete coverage.ranges
45+
expect(result).toEqual({
46+
...coverage,
47+
chunks: [
48+
{
49+
start_offset: 0,
50+
end_offset: 17,
51+
is_covered: false,
52+
},
53+
{
54+
start_offset: 17,
55+
end_offset: 38,
56+
is_covered: true,
57+
},
58+
{
59+
start_offset: 38,
60+
end_offset: 56,
61+
is_covered: false,
62+
},
63+
],
64+
} satisfies ChunkedCoverage)
65+
})
66+
67+
test('creates a single chunk when all is covered', () => {
68+
let coverage = {
69+
text: 'a { color: red; } b { color: green; } c { color: blue; }',
70+
ranges: [{ start: 0, end: 56 }],
71+
url: 'https://example.com',
72+
}
73+
let result = chunkify(coverage)
74+
delete coverage.ranges
75+
expect(result).toEqual({
76+
...coverage,
77+
chunks: [
78+
{
79+
start_offset: 0,
80+
end_offset: 56,
81+
is_covered: true,
82+
},
83+
],
84+
} satisfies ChunkedCoverage)
85+
})
86+
87+
test('creates a single chunk when none is covered', () => {
88+
let coverage = {
89+
text: 'a { color: red; } b { color: green; } c { color: blue; }',
90+
ranges: [],
91+
url: 'https://example.com',
92+
}
93+
let result = chunkify(coverage)
94+
delete coverage.ranges
95+
expect(result).toEqual({
96+
...coverage,
97+
chunks: [
98+
{
99+
start_offset: 0,
100+
end_offset: 56,
101+
is_covered: false,
102+
},
103+
],
104+
} satisfies ChunkedCoverage)
105+
})

src/lib/chunkify.ts

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
import type { Coverage } from './parse-coverage'
2+
3+
type Chunk = {
4+
start_offset: number
5+
end_offset: number
6+
is_covered: boolean
7+
}
8+
9+
export type ChunkedCoverage = Omit<Coverage, 'ranges'> & {
10+
chunks: Chunk[]
11+
}
12+
13+
function merge(stylesheet: ChunkedCoverage): ChunkedCoverage {
14+
let new_chunks: Chunk[] = []
15+
let previous_chunk: Chunk | undefined
16+
17+
for (let i = 0; i < stylesheet.chunks.length; i++) {
18+
let chunk = stylesheet.chunks.at(i)!
19+
20+
// If the current chunk is only whitespace or empty, ignore it
21+
if (/^\s+$/.test(stylesheet.text.slice(chunk.start_offset, chunk.end_offset))) {
22+
continue
23+
}
24+
25+
// let previous_chunk = stylesheet.chunks.at(i - 1)
26+
let latest_chunk = new_chunks.at(-1)
27+
28+
// merge current and previous if they are both covered or uncovered
29+
if (i > 0 && previous_chunk && latest_chunk) {
30+
if (previous_chunk.is_covered === chunk.is_covered) {
31+
latest_chunk.end_offset = chunk.end_offset
32+
// latest_chunk.css = stylesheet.text.slice(latest_chunk.start_offset, chunk.end_offset)
33+
previous_chunk = chunk
34+
continue
35+
}
36+
// If the current chunk is only whitespace or empty, add it to the previous
37+
else if (/^\s+$/.test(stylesheet.text.slice(chunk.start_offset, chunk.end_offset)) || chunk.end_offset === chunk.start_offset) {
38+
latest_chunk.end_offset = chunk.end_offset
39+
// latest_chunk.css = stylesheet.text.slice(latest_chunk.start_offset, chunk.end_offset)
40+
// do not update previous_chunk
41+
continue
42+
}
43+
}
44+
45+
previous_chunk = chunk
46+
new_chunks.push(chunk)
47+
}
48+
49+
return {
50+
...stylesheet,
51+
chunks: new_chunks,
52+
}
53+
}
54+
55+
// TODO: get rid of empty chunks, merge first/last with adjecent covered block + merge chunks
56+
export function chunkify(stylesheet: Coverage): ChunkedCoverage {
57+
let chunks = []
58+
let offset = 0
59+
60+
for (let range of stylesheet.ranges) {
61+
// Create non-covered chunk
62+
if (offset !== range.start) {
63+
chunks.push({
64+
start_offset: offset,
65+
end_offset: range.start,
66+
is_covered: false,
67+
// css: stylesheet.text.substring(offset, range.start),
68+
})
69+
offset = range.start
70+
}
71+
72+
chunks.push({
73+
start_offset: range.start,
74+
end_offset: range.end,
75+
is_covered: true,
76+
// css: stylesheet.text.substring(range.start, range.end),
77+
})
78+
offset = range.end
79+
}
80+
81+
// fill up last chunk if necessary:
82+
if (offset !== stylesheet.text.length - 1) {
83+
chunks.push({
84+
start_offset: offset,
85+
end_offset: stylesheet.text.length,
86+
is_covered: false,
87+
// css: stylesheet.text.substring(offset, stylesheet.text.length),
88+
})
89+
}
90+
91+
// console.log('before merge')
92+
// console.log(chunks)
93+
94+
let merged = merge({
95+
url: stylesheet.url,
96+
text: stylesheet.text,
97+
chunks,
98+
})
99+
100+
// console.log('after merge')
101+
// console.log(merged.chunks)
102+
103+
return merged
104+
}

src/lib/extend-ranges.test.ts

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
import { test, expect } from '@playwright/test'
2+
import { extend_ranges } from './extend-ranges'
3+
import { generate_coverage } from './test/generate-coverage'
4+
import type { Coverage } from './parse-coverage'
5+
6+
let html = `
7+
<!doctype html>
8+
<html>
9+
<head>
10+
<title>test document</title>
11+
<link rel="stylesheet" href="http://localhost/style.css">
12+
</head>
13+
<body>
14+
<h1>Hello world</h1>
15+
<p>Text</p>
16+
</body>
17+
</html>`
18+
19+
test.describe('leaves ranges intact when nothing to change', () => {
20+
test('lonely rule', async () => {
21+
let css = `body{color:green}`
22+
let coverage = (await generate_coverage(html, { link_css: css })) as Coverage[]
23+
24+
// Expect the incomplete coverage reported by the browser
25+
expect(coverage.at(0)!.ranges).toEqual([{ start: 0, end: 17 }])
26+
27+
let result = extend_ranges(coverage)
28+
expect(result.at(0)!.ranges).toEqual([{ start: 0, end: 17 }])
29+
})
30+
})
31+
32+
test.describe('@rules', () => {
33+
test('lonely @media', async () => {
34+
let css = `@media (min-width:100px){body{color:green}}`
35+
let coverage = (await generate_coverage(html, { link_css: css })) as Coverage[]
36+
37+
// Expect the incomplete coverage reported by the browser
38+
expect(coverage.at(0)!.ranges).toEqual([{ start: 7, end: 42 }]) // (min-width:100px){body{color:green}
39+
40+
let result = extend_ranges(coverage)
41+
expect(result.at(0)!.ranges).toEqual([{ start: 0, end: 43 }]) // @media (min-width:100px){body{color:green}}
42+
})
43+
44+
test.describe('adjecent to uncovered code', () => {
45+
test('@media at end', async () => {
46+
let css = `a{}@media (min-width:100px){body{color:green}}`
47+
let coverage = (await generate_coverage(html, { link_css: css })) as Coverage[]
48+
49+
// Expect the incomplete coverage reported by the browser
50+
expect(coverage.at(0)!.ranges).toEqual([{ start: 10, end: 45 }]) // (min-width:100px){body{color:green}
51+
52+
let result = extend_ranges(coverage)
53+
expect(result.at(0)!.ranges).toEqual([{ start: 3, end: 46 }]) // @media (min-width:100px){body{color:green}}
54+
})
55+
56+
test('@media at start', async () => {
57+
let css = `@media (min-width:100px){body{color:green}}a{}`
58+
let coverage = (await generate_coverage(html, { link_css: css })) as Coverage[]
59+
60+
// Expect the incomplete coverage reported by the browser
61+
expect(coverage.at(0)!.ranges).toEqual([{ start: 7, end: 42 }]) // (min-width:100px){body{color:green}
62+
63+
let result = extend_ranges(coverage)
64+
expect(result.at(0)!.ranges).toEqual([{ start: 0, end: 43 }]) // @media (min-width:100px){body{color:green}}
65+
})
66+
})
67+
68+
test.describe('adjecent to covered code', () => {
69+
test('@media at end', async () => {
70+
let css = `p{color:red}@media (min-width:100px){body{color:green}}`
71+
let coverage = (await generate_coverage(html, { link_css: css })) as Coverage[]
72+
73+
// Expect the incomplete coverage reported by the browser
74+
expect(coverage).toEqual([
75+
{
76+
url: 'http://localhost/style.css',
77+
text: css,
78+
ranges: [
79+
{ start: 0, end: 12 }, // p{color:red}
80+
{ start: 19, end: 54 }, // (min-width:100px){body{color:green}
81+
],
82+
},
83+
])
84+
85+
let result = extend_ranges(coverage)
86+
expect(result).toEqual([
87+
{
88+
url: 'http://localhost/style.css',
89+
text: css,
90+
ranges: [
91+
{ start: 0, end: 12 }, // p{color:red}
92+
{ start: 12, end: 55 }, // @media (min-width:100px){body{color:green}}
93+
],
94+
},
95+
])
96+
})
97+
98+
test('@media at start', async () => {
99+
let css = `@media (min-width:100px){body{color:green}}p{color:red}`
100+
let coverage = (await generate_coverage(html, { link_css: css })) as Coverage[]
101+
102+
// Expect the incomplete coverage reported by the browser
103+
expect(coverage).toEqual([
104+
{
105+
url: 'http://localhost/style.css',
106+
text: css,
107+
ranges: [
108+
{ start: 7, end: 42 }, // (min-width:100px){body{color:green}
109+
{ start: 43, end: 55 }, // p{color:red}
110+
],
111+
},
112+
])
113+
114+
let result = extend_ranges(coverage)
115+
expect(result).toEqual([
116+
{
117+
url: 'http://localhost/style.css',
118+
text: css,
119+
ranges: [
120+
{ start: 0, end: 43 }, // @media (min-width:100px){body{color:green}}
121+
{ start: 43, end: 55 }, // p{color:red}
122+
],
123+
},
124+
])
125+
})
126+
})
127+
})

0 commit comments

Comments
 (0)