Skip to content

Commit c06a7cd

Browse files
authored
Include coverage information in the license Range data. (#1470)
1 parent 9c8841a commit c06a7cd

21 files changed

+403
-41
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
## 0.22.23
22

33
- Upgraded SDK constraint: `^3.8.0`.
4-
- Updated `License` with `start` and `end` `Position` fields that identifies the recognized block.
4+
- Updated `License` with `Range? range` field that identifies the recognized block.
55

66
## 0.22.22
77

lib/src/license.dart

Lines changed: 46 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import 'dart:io';
88

99
import 'package:meta/meta.dart';
1010
import 'package:path/path.dart' as p;
11+
import 'package:source_span/source_span.dart';
1112

1213
import 'license_detection/license_detector.dart' hide License, Range;
1314
import 'model.dart';
@@ -41,6 +42,11 @@ Future<List<License>> detectLicenseInFile(
4142
return licenses;
4243
}
4344

45+
/// Characters and expression that are accepted as non-relevant range gaps,
46+
/// and consecutive [Range] values can be merged if they have only these
47+
/// between.
48+
final _rangeMergeRegexp = RegExp(r'^[\s\.\-\(\)\*]+$');
49+
4450
/// Returns the license(s) detected from the [SPDX-corpus][1].
4551
///
4652
/// [1]: https://spdx.org/licenses/
@@ -55,22 +61,52 @@ Future<List<License>> detectLicenseInContent(
5561
return <License>[];
5662
}
5763

64+
List<int> buildCoverages(LicenseMatch match) {
65+
final ranges = <({int start, int end})>[];
66+
// ignore: invalid_use_of_visible_for_testing_member
67+
for (final token in match.tokens) {
68+
// check to merge into last range
69+
final last = ranges.lastOrNull;
70+
if (last != null) {
71+
var mergeWithLast = false;
72+
if (last.end == token.span.start.offset) {
73+
mergeWithLast = true;
74+
} else {
75+
final textBetween = content.substring(
76+
last.end,
77+
token.span.start.offset,
78+
);
79+
if (_rangeMergeRegexp.matchAsPrefix(textBetween) != null) {
80+
mergeWithLast = true;
81+
}
82+
}
83+
if (mergeWithLast) {
84+
ranges[ranges.length - 1] = (
85+
start: last.start,
86+
end: token.span.end.offset,
87+
);
88+
continue;
89+
}
90+
}
91+
// fallback: start a new range
92+
ranges.add((start: token.span.start.offset, end: token.span.end.offset));
93+
}
94+
return ranges.expand((e) => [e.start, e.end]).toList();
95+
}
96+
5897
return licenseResult.matches.map((e) {
5998
return License(
6099
path: relativePath,
61100
spdxIdentifier: e.identifier,
62101
range: Range(
63-
start: Position(
64-
offset: e.start.offset,
65-
line: e.start.line,
66-
column: e.start.column,
67-
),
68-
end: Position(
69-
offset: e.end.offset,
70-
line: e.end.line,
71-
column: e.end.column,
72-
),
102+
start: e.start.toPosition(),
103+
end: e.end.toPosition(),
104+
coverages: buildCoverages(e),
73105
),
74106
);
75107
}).toList();
76108
}
109+
110+
extension on SourceLocation {
111+
Position toPosition() => Position(offset: offset, line: line, column: column);
112+
}

lib/src/model.dart

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,11 @@ class Range {
191191
final Position start;
192192
final Position end;
193193

194-
Range({required this.start, required this.end});
194+
/// Pair of values that indicate start-end offsets that inside the range are
195+
/// covering the license text.
196+
final List<int> coverages;
197+
198+
Range({required this.start, required this.end, required this.coverages});
195199

196200
factory Range.fromJson(Map<String, dynamic> json) => _$RangeFromJson(json);
197201

lib/src/model.g.dart

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/end2end_test.dart

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,16 @@ void main() {
110110
.replaceAll(
111111
RegExp('that was published [0-9]+ days ago'),
112112
'that was published N days ago',
113-
);
113+
)
114+
.replaceAllMapped(RegExp(r'"coverages":\[(\d+(\,\d+)+)\]'), (m) {
115+
final parts = m.group(1)!.split(',');
116+
final remaning = parts.indexed
117+
.where((p) => p.$1 < 6 || p.$1 >= parts.length - 6)
118+
.map((p) => p.$2)
119+
.join(',');
120+
return '"coverages":[$remaning]';
121+
});
122+
114123
actualMap = json.decode(updated) as Map<String, Object?>;
115124
});
116125

test/goldens/end2end/_dummy_pkg-1.0.0-null-safety.1.json

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,13 @@
3434
"offset": 1523,
3535
"line": 25,
3636
"column": 68
37-
}
37+
},
38+
"coverages": [
39+
63,
40+
836,
41+
838,
42+
1523
43+
]
3844
}
3945
}
4046
],
@@ -107,7 +113,13 @@
107113
"offset": 1523,
108114
"line": 25,
109115
"column": 68
110-
}
116+
},
117+
"coverages": [
118+
63,
119+
836,
120+
838,
121+
1523
122+
]
111123
}
112124
}
113125
],

test/goldens/end2end/async-2.11.0.json

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,13 @@
4444
"offset": 1503,
4545
"line": 26,
4646
"column": 68
47-
}
47+
},
48+
"coverages": [
49+
44,
50+
816,
51+
818,
52+
1503
53+
]
4854
}
4955
}
5056
],
@@ -145,7 +151,13 @@
145151
"offset": 1503,
146152
"line": 26,
147153
"column": 68
148-
}
154+
},
155+
"coverages": [
156+
44,
157+
816,
158+
818,
159+
1503
160+
]
149161
}
150162
}
151163
],

test/goldens/end2end/audio_service-0.18.17.json

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,21 @@
8484
"offset": 1036,
8585
"line": 19,
8686
"column": 9
87-
}
87+
},
88+
"coverages": [
89+
14,
90+
24,
91+
25,
92+
27,
93+
28,
94+
34,
95+
1011,
96+
1019,
97+
1020,
98+
1022,
99+
1023,
100+
1036
101+
]
88102
}
89103
}
90104
],
@@ -225,7 +239,21 @@
225239
"offset": 1036,
226240
"line": 19,
227241
"column": 9
228-
}
242+
},
243+
"coverages": [
244+
14,
245+
24,
246+
25,
247+
27,
248+
28,
249+
34,
250+
1011,
251+
1019,
252+
1020,
253+
1022,
254+
1023,
255+
1036
256+
]
229257
}
230258
}
231259
],

test/goldens/end2end/bulma_min-0.7.4.json

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,21 @@
3535
"offset": 1046,
3636
"line": 19,
3737
"column": 13
38-
}
38+
},
39+
"coverages": [
40+
24,
41+
34,
42+
35,
43+
37,
44+
38,
45+
44,
46+
1015,
47+
1029,
48+
1030,
49+
1032,
50+
1033,
51+
1046
52+
]
3953
}
4054
}
4155
],
@@ -115,7 +129,21 @@
115129
"offset": 1046,
116130
"line": 19,
117131
"column": 13
118-
}
132+
},
133+
"coverages": [
134+
24,
135+
34,
136+
35,
137+
37,
138+
38,
139+
44,
140+
1015,
141+
1029,
142+
1030,
143+
1032,
144+
1033,
145+
1046
146+
]
119147
}
120148
}
121149
],

test/goldens/end2end/dnd-2.0.1.json

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,15 @@
4040
"offset": 1097,
4141
"line": 20,
4242
"column": 9
43-
}
43+
},
44+
"coverages": [
45+
59,
46+
193,
47+
195,
48+
655,
49+
657,
50+
1097
51+
]
4452
}
4553
}
4654
],
@@ -129,7 +137,15 @@
129137
"offset": 1097,
130138
"line": 20,
131139
"column": 9
132-
}
140+
},
141+
"coverages": [
142+
59,
143+
193,
144+
195,
145+
655,
146+
657,
147+
1097
148+
]
133149
}
134150
}
135151
],

0 commit comments

Comments
 (0)