reffy 14.6.2 → 14.7.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "reffy",
3
- "version": "14.6.2",
3
+ "version": "14.7.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",
@@ -36,17 +36,17 @@
36
36
  "ajv-formats": "2.1.1",
37
37
  "commander": "12.0.0",
38
38
  "fetch-filecache-for-crawling": "5.1.1",
39
- "puppeteer": "22.0.0",
39
+ "puppeteer": "22.1.0",
40
40
  "semver": "^7.3.5",
41
- "web-specs": "2.79.0",
41
+ "web-specs": "3.3.0",
42
42
  "webidl2": "24.4.1"
43
43
  },
44
44
  "devDependencies": {
45
45
  "chai": "4.3.10",
46
- "mocha": "10.2.0",
46
+ "mocha": "10.3.0",
47
47
  "respec": "34.4.0",
48
48
  "respec-hljs": "2.1.1",
49
- "rollup": "4.9.6",
49
+ "rollup": "4.12.0",
50
50
  "undici": "^6.1.0"
51
51
  },
52
52
  "overrides": {
@@ -32,7 +32,8 @@
32
32
  "required": ["fragment", "type"],
33
33
  "properties": {
34
34
  "fragment": { "type": "string" },
35
- "type": { "$ref": "../common.json#/$defs/interfacetype" }
35
+ "type": { "$ref": "../common.json#/$defs/interfacetype" },
36
+ "href": { "$ref": "../common.json#/$defs/url" }
36
37
  }
37
38
  }
38
39
  },
@@ -47,7 +48,8 @@
47
48
  "required": ["fragment", "type"],
48
49
  "properties": {
49
50
  "fragment": { "type": "string" },
50
- "type": { "$ref": "../common.json#/$defs/extensiontype" }
51
+ "type": { "$ref": "../common.json#/$defs/extensiontype" },
52
+ "href": { "$ref": "../common.json#/$defs/url" }
51
53
  }
52
54
  }
53
55
  }
@@ -88,6 +88,11 @@ async function crawlSpec(spec, crawlOptions) {
88
88
  if (crawlOptions.useCrawl) {
89
89
  result = await expandSpecResult(spec, crawlOptions.useCrawl);
90
90
  }
91
+ else if (!urlToCrawl) {
92
+ // No nightly URL? That means the spec is not public (typical
93
+ // example here is ISO specs). Nothing to crawl in such cases.
94
+ result = {};
95
+ }
91
96
  else {
92
97
  result = await processSpecification(
93
98
  urlToCrawl,
@@ -120,7 +125,9 @@ async function crawlSpec(spec, crawlOptions) {
120
125
  }
121
126
 
122
127
  // Copy results back into initial spec object
123
- spec.crawled = result.crawled;
128
+ if (result.crawled) {
129
+ spec.crawled = result.crawled;
130
+ }
124
131
  if (result.crawlCacheInfo) {
125
132
  spec.crawlCacheInfo = result.crawlCacheInfo;
126
133
  }
@@ -8,17 +8,165 @@
8
8
  const webidlParser = require('../cli/parse-webidl');
9
9
 
10
10
  module.exports = {
11
- dependsOn: ['idl'],
11
+ dependsOn: ['dfns', 'idl'],
12
12
  input: 'spec',
13
13
  property: 'idlparsed',
14
14
 
15
15
  run: async function(spec, options) {
16
+ function getHref(idl, member) {
17
+ let dfnType;
18
+ let dfnFor;
19
+ let dfnOverload = 0;
20
+ let dfnName;
21
+ if (member) {
22
+ if (['iterable', 'maplike', 'setlike'].includes(member.type) ||
23
+ ['getter', 'setter', 'stringifier', 'deleter'].includes(member.special)) {
24
+ // No dfns of these types in any spec as of Feb 2024, or at least no
25
+ // no dfns that we can easily map to (for example, the HTML spec
26
+ // tends to use generic "dfn" for these).
27
+ return null;
28
+ }
29
+ if (member.type === 'operation') {
30
+ dfnType = 'method';
31
+ dfnOverload = idl.members
32
+ .filter(m => m.type === member.type && m.name === member.name)
33
+ .findIndex(m => m === member);
34
+ }
35
+ else if (member.type === 'field') {
36
+ dfnType = 'dict-member';
37
+ }
38
+ else {
39
+ dfnType = member.type;
40
+ }
41
+ dfnName = member.name ?? member.value;
42
+ if (member.type === 'constructor') {
43
+ dfnName = 'constructor';
44
+ }
45
+ dfnFor = idl.name;
46
+ }
47
+ else {
48
+ // The type of the dfn to look for is the same as the IDL type, except
49
+ // that composed IDL types ("interface mixin", "callback interface")
50
+ // only have the basic type in definitions.
51
+ dfnType = idl.type.split(' ')[0];
52
+ dfnName = idl.name;
53
+ }
54
+
55
+ if (!['attribute', 'callback', 'const', 'constructor',
56
+ 'dict-member', 'dictionary', 'enum', 'enum-value',
57
+ 'interface', 'method', 'namespace', 'typedef'
58
+ ].includes(dfnType)) {
59
+ console.error(`[error] Found unexpected IDL type "${dfnType}" in ${spec.shortname}`);
60
+ }
61
+
62
+ const dfnNames = [];
63
+ if (dfnType === 'enum-value') {
64
+ // Bikeshed keeps wrapping quotes in the dfn linking text, not ReSpec.
65
+ dfnNames.push(dfnName);
66
+ dfnNames.push(`"${dfnName}"`);
67
+ }
68
+ else if (dfnType === 'method' || dfnType === 'constructor') {
69
+ // Spec authoring tools use different naming conventions in dfns:
70
+ // - For variadic arguments, Bikeshed adds "...", not ReSpec.
71
+ // - For overloads, Bikeshed relies on argument names, ReSpec adds
72
+ // "!overload-x" to the name of the second, third, etc. overloads.
73
+ // - The HTML spec sometimes excludes argument names from method dfns.
74
+ // We'll give these different variants a try, roughly starting from the
75
+ // most specific ones, in other words starting by looking at a specific
76
+ // overload dfn.
77
+ // When a method has overloads but the spec only has one dfn for the
78
+ // first variant, this approach will link the other overloads to that
79
+ // first dfn. That's slightly incorrect but a good enough approximation
80
+ // in practice.
81
+ const argsVariadic = member.arguments.map(arg => (arg.variadic ? '...' : '') + arg.name);
82
+ const args = member.arguments.map(arg => arg.name);
83
+ dfnNames.push(`${dfnName}!overload-${dfnOverload}(${args.join(', ')})`);
84
+ dfnNames.push(`${dfnName}(${argsVariadic.join(', ')})`);
85
+ dfnNames.push(`${dfnName}(${args.join(', ')})`);
86
+ dfnNames.push(`${dfnName}()`);
87
+ }
88
+ else {
89
+ dfnNames.push(dfnName);
90
+ }
91
+
92
+ // Look for definitions that look like good initial candidates
93
+ const candidateDfns = spec.dfns.filter(dfn =>
94
+ dfn.type === dfnType && (dfnFor ? dfn.for.includes(dfnFor) : true));
95
+
96
+ // Look for names in turn in that list of candidates.
97
+ for (const name of dfnNames) {
98
+ const dfns = candidateDfns.filter(dfn => dfn.linkingText.includes(name));
99
+ if (dfns.length > 0) {
100
+ if (dfns.length > 1) {
101
+ const forLabel = dfnFor ? ` for \`${dfnFor}\`` : '';
102
+ console.warn(`[warn] More than one dfn for ${dfnType} \`${dfnName}\`${forLabel} in [${spec.shortname}](${spec.crawled}).`);
103
+ return null;
104
+ }
105
+ else {
106
+ return dfns[0].href;
107
+ }
108
+ }
109
+ }
110
+
111
+ return null;
112
+ }
113
+
16
114
  if (!spec?.idl) {
17
115
  return spec;
18
116
  }
19
117
  try {
20
118
  spec.idlparsed = await webidlParser.parse(spec.idl);
21
119
  spec.idlparsed.hasObsoleteIdl = webidlParser.hasObsoleteIdl(spec.idl);
120
+
121
+ if (spec.dfns) {
122
+ for (const idl of Object.values(spec.idlparsed.idlNames)) {
123
+ const href = getHref(idl);
124
+ if (href) {
125
+ idl.href = href;
126
+ }
127
+
128
+ if (idl.values) {
129
+ for (const value of idl.values) {
130
+ const href = getHref(idl, value);
131
+ if (href) {
132
+ value.href = href;
133
+ }
134
+ }
135
+ }
136
+
137
+ if (idl.members) {
138
+ for (const member of idl.members) {
139
+ const href = getHref(idl, member);
140
+ if (href) {
141
+ member.href = href;
142
+ }
143
+ }
144
+ }
145
+ }
146
+
147
+ for (const extendedIdl of Object.values(spec.idlparsed.idlExtendedNames)) {
148
+ for (const idl of extendedIdl) {
149
+ // No dfn for the extension, we can only link specific members
150
+ if (idl.values) {
151
+ for (const value of idl.values) {
152
+ const href = getHref(idl, value);
153
+ if (href) {
154
+ value.href = href;
155
+ }
156
+ }
157
+ }
158
+
159
+ if (idl.members) {
160
+ for (const member of idl.members) {
161
+ const href = getHref(idl, member);
162
+ if (href) {
163
+ member.href = href;
164
+ }
165
+ }
166
+ }
167
+ }
168
+ }
169
+ }
22
170
  }
23
171
  catch (err) {
24
172
  // IDL content is invalid and cannot be parsed.