reffy 7.2.7 → 7.2.10

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "reffy",
3
- "version": "7.2.7",
3
+ "version": "7.2.10",
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,9 +34,9 @@
34
34
  "abortcontroller-polyfill": "1.7.3",
35
35
  "commander": "9.3.0",
36
36
  "fetch-filecache-for-crawling": "4.1.0",
37
- "puppeteer": "15.3.2",
37
+ "puppeteer": "15.4.0",
38
38
  "semver": "^7.3.5",
39
- "web-specs": "2.16.0",
39
+ "web-specs": "2.17.0",
40
40
  "webidl2": "24.2.2"
41
41
  },
42
42
  "devDependencies": {
@@ -225,6 +225,12 @@ const extractValueSpaces = doc => {
225
225
  }
226
226
  };
227
227
 
228
+ // Regular expression to use to split production rules:
229
+ // Split on the space that precedes a term immediately before an equal sign
230
+ // that is not wrapped in quotes (an equal sign wrapped in quotes is part of
231
+ // actual value syntax)
232
+ const reSplitRules = /\s(?=[^\s]+?\s*?=[^'])/;
233
+
228
234
  // Extract all dfns with data-dfn-type="type" or data-dfn-type="function"
229
235
  // but ignore definitions in <pre> as they do not always use dfns, as in
230
236
  // https://drafts.csswg.org/css-values-4/#calc-syntax
@@ -246,7 +252,15 @@ const extractValueSpaces = doc => {
246
252
  const text = parent.textContent.trim();
247
253
  if (text.match(/\s?=\s/)) {
248
254
  // Definition appears in a "prod = foo" text, that's all good
249
- parseProductionRule(text, { pureSyntax: true });
255
+ // ... except in css-easing-2 draft where text also contains another
256
+ // production rule as a child of the first one:
257
+ // https://drafts.csswg.org/css-easing-2/#typedef-step-easing-function
258
+ const prod = text.split(reSplitRules)
259
+ .find(p => p.trim().startsWith(dfn.textContent.trim()));
260
+ if (!prod) {
261
+ throw new Error(`Production rule for ${dfn.textContent.trim()} found has unexpected format`);
262
+ }
263
+ parseProductionRule(prod, { pureSyntax: true });
250
264
  }
251
265
  else if (dfn.textContent.trim().match(/^[a-zA-Z_][a-zA-Z0-9_\-]+\([^\)]+\)$/)) {
252
266
  // Definition is "prod(foo bar)", create a "prod() = prod(foo bar)" entry
@@ -323,7 +337,7 @@ const extractValueSpaces = doc => {
323
337
  })
324
338
  .map(el => el.textContent)
325
339
  .map(val => val.replace(/\/\*[^]*?\*\//gm, '')) // Drop comments
326
- .map(val => val.split(/\n(?=[^\n]*\s?=\s)/m)) // Separate definitions
340
+ .map(val => val.split(reSplitRules)) // Separate definitions
327
341
  .flat()
328
342
  .filter(text => text.match(/\s?=\s/))
329
343
  .map(text => parseProductionRule(text, { pureSyntax: true }));
@@ -41,14 +41,11 @@ export default function (spec) {
41
41
  function fromEventElementToTargetInterfaces(eventEl) {
42
42
  if (!eventEl) return;
43
43
 
44
- console.log(`[reffy] ${eventEl.textContent}`);
45
-
46
44
  if (eventEl.dataset?.dfnFor || eventEl.dataset?.linkFor) {
47
45
  return (eventEl.dataset.dfnFor || eventEl.dataset.linkFor).split(",").map(t => t.trim());
48
46
  } else if (eventEl.getAttribute("href")?.startsWith("#")) {
49
47
  const dfn = document.getElementById(eventEl.getAttribute("href").slice(1));
50
48
  if (dfn && dfn.dataset?.dfnFor) {
51
- console.log(`[reffy] ${eventEl.textContent} dfnFor ${dfn.dataset.dfnFor.split(",").map(t => t.trim())}`);
52
49
  return dfn.dataset.dfnFor.split(",").map(t => t.trim());
53
50
  }
54
51
  } else if (handledEventNames[eventEl.textContent]?.length) {
@@ -56,7 +53,6 @@ export default function (spec) {
56
53
  const matchingInterfaces = handledEventNames[eventEl.textContent];
57
54
  if (matchingInterfaces.length === 1) {
58
55
  // only one such handler, we assume it's a match
59
- console.log(`[reffy] ${eventEl.textContent} found ${matchingInterfaces}`);
60
56
  return matchingInterfaces;
61
57
  } else {
62
58
  console.error(`[reffy] Multiple event handler named ${eventEl.textContent}, cannot associate reliably to an interface in ${spec.title}`);
@@ -106,12 +102,12 @@ export default function (spec) {
106
102
  if (el.tagName === "DFN" && el.id) {
107
103
  event.href = href(el);
108
104
  } else if (el.tagName === "A") {
109
- if (!el.getAttribute("href").startsWith("https://")) {
110
- const url = new URL(el.href);
111
- event.href = href(document.getElementById(url.hash.slice(1)));
112
- } else {
113
- event.href = el.href;
114
- }
105
+ if (!el.getAttribute("href").startsWith("https://")) {
106
+ const url = new URL(el.href);
107
+ event.href = href(document.getElementById(url.hash.slice(1)));
108
+ } else {
109
+ event.href = el.href;
110
+ }
115
111
  }
116
112
  event.src = { format: "summary table", href: href(el.closest('*[id]')) };
117
113
  event.type = eventEl.textContent.trim();
@@ -124,9 +120,9 @@ export default function (spec) {
124
120
  tr.querySelector(`td:nth-child(${interfaceColumn + 1}) a`)?.textContent ??
125
121
  tr.querySelector(`td:nth-child(${interfaceColumn + 1}) code`)?.textContent;
126
122
  }
127
- if (targetsColumn >= 0 && !event.targets) {
128
- event.targets = tr.querySelector(`td:nth-child(${targetsColumn + 1})`)?.textContent?.split(',').map(t => t.trim());
129
- }
123
+ if (targetsColumn >= 0 && !event.targets) {
124
+ event.targets = tr.querySelector(`td:nth-child(${targetsColumn + 1})`)?.textContent?.split(',').map(t => t.trim());
125
+ }
130
126
  events.push(event);
131
127
  eventEl.replaceWith(origEventEl);
132
128
  });
@@ -209,8 +205,8 @@ export default function (spec) {
209
205
  } else {
210
206
  event.type = name;
211
207
  // looking at the element following the link
212
- // if its content match the name of the event
213
- const eventEl = a.nextElementSibling?.textContent?.trim() === event.type ? a.nextElementSibling.querySelector("a,dfn") || a.nextElementSibling : null;
208
+ // if its content match the name of the event
209
+ const eventEl = a.nextElementSibling?.textContent?.trim() === event.type ? a.nextElementSibling.querySelector("a,dfn") || a.nextElementSibling : null;
214
210
  if (eventEl) {
215
211
  if (eventEl.tagName === "A" && eventEl.getAttribute("href")) {
216
212
  // use the target of the link as our href
@@ -231,7 +227,7 @@ export default function (spec) {
231
227
  while ((curEl = curEl.nextElementSibling)) {
232
228
  if (curEl.textContent.match(/^([A-Z]+[a-z0-9]*)+Event$/)) {
233
229
  iface = curEl.textContent.trim();
234
- break;
230
+ break;
235
231
  }
236
232
  }
237
233
  if (iface) {
@@ -326,20 +322,20 @@ export default function (spec) {
326
322
  // of the section where the definitions are located
327
323
  let currentEl = container.parentNode;
328
324
  while(currentEl) {
329
- if (currentEl.tagName.match(/^H[1-6]$/)) {
330
- break;
331
- }
332
- currentEl = currentEl.previousElementSibling;
325
+ if (currentEl.tagName.match(/^H[1-6]$/)) {
326
+ break;
327
+ }
328
+ currentEl = currentEl.previousElementSibling;
333
329
  }
334
330
  const interfaceEl = currentEl?.querySelector("code");
335
331
  if (interfaceEl?.textContent?.match(/^[A-Z][a-z]+Event$/)) {
336
- iface = interfaceEl.textContent;
332
+ iface = interfaceEl.textContent;
337
333
  }
338
334
  }
339
335
  const ev = events.find(e => isSameEvent(event, e));
340
336
  if (!ev) {
341
337
  if (iface) {
342
- event.interface = iface;
338
+ event.interface = iface;
343
339
  }
344
340
  event.bubbles = bubbles;
345
341
  events.push(event);
@@ -351,7 +347,7 @@ export default function (spec) {
351
347
  ev.interface = iface;
352
348
  }
353
349
  if (!ev.href && event.href) {
354
- ev.href = event.href;
350
+ ev.href = event.href;
355
351
  }
356
352
  if (bubbles !== undefined) {
357
353
  ev.bubbles = bubbles;
package/src/lib/util.js CHANGED
@@ -605,7 +605,7 @@ async function processSpecification(spec, processFunction, args, options) {
605
605
  window.document.head.querySelector("script[src*='respec']");
606
606
 
607
607
  function sleep(ms) {
608
- return new Promise(resolve => setTimeout(resolve, ms));
608
+ return new Promise(resolve => setTimeout(resolve, ms, 'slept'));
609
609
  }
610
610
 
611
611
  async function isReady(counter) {
@@ -614,7 +614,10 @@ async function processSpecification(spec, processFunction, args, options) {
614
614
  throw new Error('Respec generation took too long');
615
615
  }
616
616
  if (window.document.respec?.ready) {
617
- await window.document.respec.ready;
617
+ const res = await Promise.race([window.document.respec.ready, sleep(60000)]);
618
+ if (res === 'slept') {
619
+ throw new Error('Respec generation took too long');
620
+ }
618
621
  }
619
622
  else if (usesRespec) {
620
623
  await sleep(1000);