reffy 8.0.2 → 9.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +5 -5
- package/src/browserlib/extract-cssdfn.mjs +52 -8
- package/src/lib/util.js +6 -2
- package/src/postprocessing/events.js +48 -32
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "reffy",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "9.0.0",
|
|
4
4
|
"description": "W3C/WHATWG spec dependencies exploration companion. Features a short set of tools to study spec references as well as WebIDL term definitions and references found in W3C specifications.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -34,18 +34,18 @@
|
|
|
34
34
|
"abortcontroller-polyfill": "1.7.3",
|
|
35
35
|
"commander": "9.4.0",
|
|
36
36
|
"fetch-filecache-for-crawling": "4.1.0",
|
|
37
|
-
"puppeteer": "
|
|
37
|
+
"puppeteer": "16.1.1",
|
|
38
38
|
"semver": "^7.3.5",
|
|
39
|
-
"web-specs": "2.
|
|
39
|
+
"web-specs": "2.19.0",
|
|
40
40
|
"webidl2": "24.2.2"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"chai": "4.3.6",
|
|
44
44
|
"mocha": "10.0.0",
|
|
45
45
|
"nock": "13.2.9",
|
|
46
|
-
"respec": "32.
|
|
46
|
+
"respec": "32.2.3",
|
|
47
47
|
"respec-hljs": "2.1.1",
|
|
48
|
-
"rollup": "2.
|
|
48
|
+
"rollup": "2.78.0"
|
|
49
49
|
},
|
|
50
50
|
"scripts": {
|
|
51
51
|
"test": "mocha --recursive tests/"
|
|
@@ -13,15 +13,37 @@ import informativeSelector from './informative-selector.mjs';
|
|
|
13
13
|
export default function () {
|
|
14
14
|
let res = {
|
|
15
15
|
properties: extractTableDfns(document, 'propdef', { unique: true }),
|
|
16
|
-
|
|
16
|
+
atrules: {},
|
|
17
17
|
valuespaces: extractValueSpaces(document)
|
|
18
18
|
};
|
|
19
|
+
let descriptors = extractTableDfns(document, 'descdef', { unique: false });
|
|
19
20
|
|
|
20
21
|
// Try old recipes if we couldn't extract anything
|
|
21
22
|
if ((Object.keys(res.properties).length === 0) &&
|
|
22
|
-
(Object.keys(
|
|
23
|
+
(Object.keys(descriptors).length === 0)) {
|
|
23
24
|
res.properties = extractDlDfns(document, 'propdef', { unique: true });
|
|
24
|
-
|
|
25
|
+
descriptors = extractDlDfns(document, 'descdef', { unique: false });
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Move at-rules definitions from valuespaces to at-rules structure
|
|
29
|
+
for (const [name, dfn] of Object.entries(res.valuespaces)) {
|
|
30
|
+
if (name.startsWith('@')) {
|
|
31
|
+
if (!res.atrules[name]) {
|
|
32
|
+
res.atrules[name] = Object.assign(dfn, { descriptors: [] });
|
|
33
|
+
}
|
|
34
|
+
delete res.valuespaces[name];
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Move descriptors to at-rules structure
|
|
39
|
+
for (const [name, desclist] of Object.entries(descriptors)) {
|
|
40
|
+
for (const desc of desclist) {
|
|
41
|
+
const rule = desc.for;
|
|
42
|
+
if (!res.atrules[rule]) {
|
|
43
|
+
res.atrules[rule] = { descriptors: [] };
|
|
44
|
+
}
|
|
45
|
+
res.atrules[rule].descriptors.push(desc);
|
|
46
|
+
}
|
|
25
47
|
}
|
|
26
48
|
|
|
27
49
|
return res;
|
|
@@ -198,6 +220,9 @@ const extractDlDfns = (doc, className, options) =>
|
|
|
198
220
|
* Definitions with `data-dfn-type` attribute set to `value` are not extracted
|
|
199
221
|
* on purpose as they are typically namespaced to another construct (through a
|
|
200
222
|
* `data-dfn-for` attribute.
|
|
223
|
+
*
|
|
224
|
+
* The function also extracts syntax of at-rules (name starts with '@') defined
|
|
225
|
+
* in "pre.prod" blocks.
|
|
201
226
|
*/
|
|
202
227
|
const extractValueSpaces = doc => {
|
|
203
228
|
let res = {};
|
|
@@ -213,16 +238,27 @@ const extractValueSpaces = doc => {
|
|
|
213
238
|
.replace(/\/\*[^]*?\*\//gm, '') // Drop comments
|
|
214
239
|
.split(/\s?=\s/)
|
|
215
240
|
.map(s => s.trim().replace(/\s+/g, ' '));
|
|
216
|
-
|
|
217
|
-
|
|
241
|
+
|
|
242
|
+
function addValuespace(name, value) {
|
|
218
243
|
if (!(name in res)) {
|
|
219
244
|
res[name] = {};
|
|
220
245
|
}
|
|
221
246
|
if (!res[name].value || (pureSyntax && !res[name].pureSyntax)) {
|
|
222
|
-
res[name].value = normalize(
|
|
247
|
+
res[name].value = normalize(value);
|
|
223
248
|
res[name].pureSyntax = pureSyntax;
|
|
224
249
|
}
|
|
225
250
|
}
|
|
251
|
+
|
|
252
|
+
if (nameAndValue[0].match(/^<.*>$|^.*\(\)$/)) {
|
|
253
|
+
// Regular valuespace
|
|
254
|
+
addValuespace(
|
|
255
|
+
nameAndValue[0].replace(/^(.*\(\))$/, '<$1>'),
|
|
256
|
+
nameAndValue[1]);
|
|
257
|
+
}
|
|
258
|
+
else if (nameAndValue[0].match(/^@[a-z\-]+$/)) {
|
|
259
|
+
// At-rule syntax
|
|
260
|
+
addValuespace(nameAndValue[0], nameAndValue[1]);
|
|
261
|
+
}
|
|
226
262
|
};
|
|
227
263
|
|
|
228
264
|
// Regular expression to use to split production rules:
|
|
@@ -351,8 +387,16 @@ const extractValueSpaces = doc => {
|
|
|
351
387
|
.map(val => val.replace(/\/\*[^]*?\*\//gm, '')) // Drop comments
|
|
352
388
|
.map(val => val.split(reSplitRules)) // Separate definitions
|
|
353
389
|
.flat()
|
|
354
|
-
.
|
|
355
|
-
.map(text =>
|
|
390
|
+
.map(text => text.trim())
|
|
391
|
+
.map(text => {
|
|
392
|
+
if (text.match(/\s?=\s/)) {
|
|
393
|
+
return parseProductionRule(text, { pureSyntax: true });
|
|
394
|
+
}
|
|
395
|
+
else if (text.startsWith('@')) {
|
|
396
|
+
const name = text.split(' ')[0];
|
|
397
|
+
return parseProductionRule(`${name} = ${text}`, { pureSyntax: true });
|
|
398
|
+
}
|
|
399
|
+
});
|
|
356
400
|
|
|
357
401
|
// Don't keep the info on whether value comes from a pure syntax section
|
|
358
402
|
Object.values(res).map(value => delete value.pureSyntax);
|
package/src/lib/util.js
CHANGED
|
@@ -946,9 +946,13 @@ async function createFolderIfNeeded(folder) {
|
|
|
946
946
|
* the tree.
|
|
947
947
|
*/
|
|
948
948
|
const trees = {
|
|
949
|
-
// DOM tree:
|
|
949
|
+
// The DOM tree is defined through "get the parent" algorithms:
|
|
950
950
|
// https://dom.spec.whatwg.org/#node-trees
|
|
951
|
-
|
|
951
|
+
// https://dom.spec.whatwg.org/#get-the-parent
|
|
952
|
+
// - Node -> Node
|
|
953
|
+
// - Document -> Window
|
|
954
|
+
// - ShadowRoot -> Element (both derive from Node, so covered by Node -> Node)
|
|
955
|
+
'dom': ['Window', 'Document', 'Node'],
|
|
952
956
|
|
|
953
957
|
// IndexedDB tree (defined through "get the parent" algorithms)
|
|
954
958
|
// https://www.w3.org/TR/IndexedDB/#ref-for-get-the-parent%E2%91%A0
|
|
@@ -46,7 +46,6 @@ module.exports = {
|
|
|
46
46
|
for (const event of events) {
|
|
47
47
|
expandMixinTargets(event, mixins);
|
|
48
48
|
setBubblingPerTarget(event, parsedInterfaces);
|
|
49
|
-
cleanTargetInTrees(event, parsedInterfaces);
|
|
50
49
|
}
|
|
51
50
|
|
|
52
51
|
// Consolidate events extended in other specs
|
|
@@ -69,6 +68,7 @@ module.exports = {
|
|
|
69
68
|
return events
|
|
70
69
|
.filter(event => !eventsToDrop.includes(event))
|
|
71
70
|
.map(event => {
|
|
71
|
+
cleanTargetInterfaces(event, parsedInterfaces);
|
|
72
72
|
delete event.spec;
|
|
73
73
|
return event;
|
|
74
74
|
});
|
|
@@ -135,41 +135,57 @@ function setBubblingPerTarget(event, parsedInterfaces) {
|
|
|
135
135
|
}
|
|
136
136
|
|
|
137
137
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
138
|
+
/**
|
|
139
|
+
* Filter the list of target interfaces to remove those that don't need to
|
|
140
|
+
* appear explicitly because they are de facto already covered by another entry
|
|
141
|
+
* in the list.
|
|
142
|
+
*
|
|
143
|
+
* Two reasons to drop a target interface t from the list:
|
|
144
|
+
* 1. There exists another target interface o with similar bubbling properties
|
|
145
|
+
* for the event and t inherits from o. If event fires at o, it can de facto
|
|
146
|
+
* fire at t.
|
|
147
|
+
* 2. There exists another target interface o such that t and o belong to the
|
|
148
|
+
* same bubbling tree, o is at a deeper level than t in the bubbling tree, and
|
|
149
|
+
* event bubbles when it fires at o. Event will de facto fire at t through
|
|
150
|
+
* bubbling when that happens.
|
|
151
|
+
*/
|
|
152
|
+
function cleanTargetInterfaces(event, parsedInterfaces) {
|
|
153
|
+
// Helper function that returns true if the iface interface inherits from the
|
|
154
|
+
// base interface
|
|
155
|
+
function inheritsFrom(iface, base) {
|
|
156
|
+
while (iface) {
|
|
157
|
+
if (iface === base) {
|
|
158
|
+
return true;
|
|
159
|
+
}
|
|
160
|
+
iface = parsedInterfaces.find(i => i.name === iface)?.inheritance;
|
|
146
161
|
}
|
|
162
|
+
return false;
|
|
147
163
|
}
|
|
148
|
-
return false;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
164
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
let filteredTargets = [];
|
|
155
|
-
for (let {target, bubbles} of targets) {
|
|
156
|
-
const treeInfo = getInterfaceTreeInfo(target, parsedInterfaces);
|
|
157
|
-
if (!treeInfo) { // Not in a tree, we keep it in
|
|
158
|
-
filteredTargets.push({target});
|
|
159
|
-
continue;
|
|
160
|
-
}
|
|
161
|
-
const { tree, depth } = treeInfo;
|
|
162
|
-
const currentDeepest = deepestInTrees[tree]?.target;
|
|
163
|
-
if (currentDeepest) {
|
|
164
|
-
const { depth: currentDeepestDepth } = getInterfaceTreeInfo(currentDeepest, parsedInterfaces);
|
|
165
|
-
if (depth > currentDeepestDepth) {
|
|
166
|
-
deepestInTrees[tree] = {target, bubbles};
|
|
167
|
-
}
|
|
168
|
-
} else {
|
|
169
|
-
deepestInTrees[tree] = {target, bubbles};
|
|
170
|
-
}
|
|
165
|
+
if (!event.targets) {
|
|
166
|
+
return;
|
|
171
167
|
}
|
|
172
|
-
|
|
168
|
+
|
|
169
|
+
event.targets = event.targets
|
|
170
|
+
.filter(({ target, bubbles }) =>
|
|
171
|
+
// Drop if an ancestor in the inheritance chain is already there
|
|
172
|
+
!event.targets.find(({ target: other, bubbles: otherBubbles}) =>
|
|
173
|
+
target !== other &&
|
|
174
|
+
bubbles === otherBubbles &&
|
|
175
|
+
inheritsFrom(target, other)))
|
|
176
|
+
.filter(({ target, bubbles }) => {
|
|
177
|
+
// Drop if a deeper bubbling target interface in the tree is already there
|
|
178
|
+
const targetTreeInfo = getInterfaceTreeInfo(target, parsedInterfaces);
|
|
179
|
+
return !targetTreeInfo ||
|
|
180
|
+
!event.targets.find(({ target: other, bubbles: otherBubbles }) => {
|
|
181
|
+
if (other === target) {
|
|
182
|
+
return false;
|
|
183
|
+
}
|
|
184
|
+
const otherTreeInfo = getInterfaceTreeInfo(other, parsedInterfaces);
|
|
185
|
+
return otherTreeInfo?.tree === targetTreeInfo.tree &&
|
|
186
|
+
otherBubbles && otherTreeInfo.depth > targetTreeInfo.depth;
|
|
187
|
+
});
|
|
188
|
+
});
|
|
173
189
|
}
|
|
174
190
|
|
|
175
191
|
|