reffy 20.0.13 → 20.0.14
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/LICENSE +21 -21
- package/README.md +151 -151
- package/index.js +29 -29
- package/package.json +3 -3
- package/reffy.js +324 -324
- package/schemas/browserlib/extract-algorithms.json +52 -52
- package/schemas/browserlib/extract-cssdfn.json +108 -108
- package/schemas/browserlib/extract-dfns.json +90 -90
- package/schemas/browserlib/extract-elements.json +17 -17
- package/schemas/browserlib/extract-events.json +31 -31
- package/schemas/browserlib/extract-headings.json +19 -19
- package/schemas/browserlib/extract-ids.json +7 -7
- package/schemas/browserlib/extract-links.json +12 -12
- package/schemas/browserlib/extract-refs.json +12 -12
- package/schemas/common.json +876 -876
- package/schemas/files/extracts/algorithms.json +12 -12
- package/schemas/files/extracts/css.json +16 -16
- package/schemas/files/extracts/dfns.json +12 -12
- package/schemas/files/extracts/elements.json +12 -12
- package/schemas/files/extracts/events.json +12 -12
- package/schemas/files/extracts/headings.json +12 -12
- package/schemas/files/extracts/ids.json +12 -12
- package/schemas/files/extracts/links.json +12 -12
- package/schemas/files/extracts/refs.json +12 -12
- package/schemas/files/index.json +59 -59
- package/schemas/postprocessing/events.json +50 -50
- package/schemas/postprocessing/idlnames-parsed.json +27 -27
- package/schemas/postprocessing/idlnames.json +17 -17
- package/schemas/postprocessing/idlparsed.json +67 -67
- package/src/browserlib/clone-and-clean.mjs +24 -24
- package/src/browserlib/create-outline.mjs +353 -353
- package/src/browserlib/extract-algorithms.mjs +723 -723
- package/src/browserlib/extract-cddl.mjs +125 -125
- package/src/browserlib/extract-dfns.mjs +1093 -1093
- package/src/browserlib/extract-headings.mjs +76 -76
- package/src/browserlib/extract-ids.mjs +28 -28
- package/src/browserlib/extract-links.mjs +45 -45
- package/src/browserlib/extract-references.mjs +308 -308
- package/src/browserlib/extract-webidl.mjs +89 -89
- package/src/browserlib/get-absolute-url.mjs +29 -29
- package/src/browserlib/get-code-elements.mjs +20 -20
- package/src/browserlib/get-generator.mjs +26 -26
- package/src/browserlib/get-lastmodified-date.mjs +13 -13
- package/src/browserlib/get-revision.mjs +12 -12
- package/src/browserlib/get-title.mjs +14 -14
- package/src/browserlib/informative-selector.mjs +24 -24
- package/src/browserlib/map-ids-to-headings.mjs +173 -173
- package/src/browserlib/reffy.json +85 -85
- package/src/browserlib/trim-spaces.mjs +35 -35
- package/src/cli/check-missing-dfns.js +587 -587
- package/src/cli/merge-crawl-results.js +132 -132
- package/src/cli/parse-webidl.js +447 -447
- package/src/lib/css-grammar-parse-tree.schema.json +109 -109
- package/src/lib/css-grammar-parser.js +440 -440
- package/src/lib/fetch.js +51 -51
- package/src/lib/markdown-report.js +360 -360
- package/src/lib/mock-server.js +218 -218
- package/src/lib/post-processor.js +322 -322
- package/src/lib/throttled-queue.js +129 -129
- package/src/postprocessing/annotate-links.js +41 -41
- package/src/postprocessing/csscomplete.js +48 -48
- package/src/postprocessing/idlnames.js +391 -391
- package/src/postprocessing/idlparsed.js +179 -179
- package/src/postprocessing/patch-dfns.js +51 -51
- package/src/specs/missing-css-rules.json +197 -197
- package/src/specs/spec-equivalents.json +149 -149
- package/src/browserlib/extract-editors.mjs~ +0 -14
- package/src/browserlib/extract-events.mjs~ +0 -3
- package/src/browserlib/generate-es-dfn-report.sh~ +0 -4
- package/src/browserlib/get-revision.mjs~ +0 -7
- package/src/cli/csstree-grammar-check.js +0 -28
- package/src/cli/csstree-grammar-check.js~ +0 -10
- package/src/cli/csstree-grammar-parser.js +0 -11
- package/src/cli/csstree-grammar-parser.js~ +0 -1
- package/src/cli/extract-editors.js~ +0 -38
- package/src/cli/process-specs.js~ +0 -28
- package/src/postprocessing/annotate-links.js~ +0 -8
- package/src/postprocessing/events.js~ +0 -245
|
@@ -1,323 +1,323 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* The post-processor runs post-processing modules against crawl results.
|
|
4
|
-
*
|
|
5
|
-
* There are two types of post-processing modules:
|
|
6
|
-
* 1. Modules that run against the result of crawling an individual spec. Such
|
|
7
|
-
* modules take the spec crawl result as input and typically update it in place
|
|
8
|
-
* 2. Modules that run against an entire crawl result. Such modules take the
|
|
9
|
-
* entire crawl result as input and return whatever structure they would like
|
|
10
|
-
* to return.
|
|
11
|
-
*
|
|
12
|
-
* The post-processor exposes two main functions:
|
|
13
|
-
* - run() to run a post-processing module against crawl results or against a
|
|
14
|
-
* spec crawl result (depending on the module)
|
|
15
|
-
* - save() to save processing results to files
|
|
16
|
-
*
|
|
17
|
-
* A post-processing module needs to expose the following properties and
|
|
18
|
-
* functions:
|
|
19
|
-
* - dependsOn: list of crawl result info that the module depends on. Values
|
|
20
|
-
* include "css", "dfns", "idl", as well as info that other post-processing
|
|
21
|
-
* modules may generate such as "idlparsed".
|
|
22
|
-
* - input: either "crawl" or "spec". Default is "spec". Tells whether the
|
|
23
|
-
* module operates on a spec crawl result or on the entire crawl result
|
|
24
|
-
* - property: When "input" is "spec", gives the name of the property that
|
|
25
|
-
* will be set in the spec crawl result when the post-processing module runs
|
|
26
|
-
* and of the folder that will contain the spec extracts (unless module has its
|
|
27
|
-
* "save" logic). For modules that run at the crawl level, gives the name of
|
|
28
|
-
* the final extract file that gets created (unless module has its own "save"
|
|
29
|
-
* logic).
|
|
30
|
-
* - run: Async function to call to apply the post-processing module. The
|
|
31
|
-
* function is called with either a spec crawl result of the entire crawl result
|
|
32
|
-
* depending on "input". Second parameter is the crawl options object. The
|
|
33
|
-
* function should return the created structure when "input" is "crawl" and
|
|
34
|
-
* the updated spec crawl result when "input" is "spec". Note the function
|
|
35
|
-
* may update the spec crawl result in place.
|
|
36
|
-
* - save: Function to call to save the results of the post-processing module.
|
|
37
|
-
* The function is called with the returned result of running the
|
|
38
|
-
* post-processing module. Second parameter is the crawl options object. The
|
|
39
|
-
* function is only needed if "save" needs to do specific things that the
|
|
40
|
-
* post-processor cannot do on its own. Function must return the relative path
|
|
41
|
-
* to the file that was saved
|
|
42
|
-
* - extractsPerSeries: A boolean flag that tells the crawler that it should
|
|
43
|
-
* clean up extract afterwards to produce extracts per series instead of
|
|
44
|
-
* extracts per spec. The flag is only meaningful if module runs at the spec
|
|
45
|
-
* level and if "property" is set.
|
|
46
|
-
*
|
|
47
|
-
* @module
|
|
48
|
-
*/
|
|
49
|
-
|
|
50
|
-
import fs from 'node:fs';
|
|
51
|
-
import path from 'node:path';
|
|
52
|
-
import { pathToFileURL } from 'node:url';
|
|
53
|
-
import { createFolderIfNeeded, shouldSaveToFile } from './util.js';
|
|
54
|
-
import csscomplete from '../postprocessing/csscomplete.js';
|
|
55
|
-
import cssmerge from '../postprocessing/cssmerge.js';
|
|
56
|
-
import events from '../postprocessing/events.js';
|
|
57
|
-
import idlnames from '../postprocessing/idlnames.js';
|
|
58
|
-
import idlparsed from '../postprocessing/idlparsed.js';
|
|
59
|
-
import annotatelinks from '../postprocessing/annotate-links.js';
|
|
60
|
-
import patchdfns from '../postprocessing/patch-dfns.js';
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Core post-processing modules
|
|
65
|
-
*/
|
|
66
|
-
const modules = {
|
|
67
|
-
csscomplete,
|
|
68
|
-
cssmerge,
|
|
69
|
-
events,
|
|
70
|
-
idlnames,
|
|
71
|
-
idlparsed,
|
|
72
|
-
annotatelinks,
|
|
73
|
-
patchdfns
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Custom post-processing modules
|
|
79
|
-
*/
|
|
80
|
-
const customModules = {};
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Loads post-processing modules once and for all
|
|
85
|
-
*/
|
|
86
|
-
async function loadModules(mods) {
|
|
87
|
-
for (const mod of mods) {
|
|
88
|
-
if (typeof mod === 'string') {
|
|
89
|
-
if (modules[mod]) {
|
|
90
|
-
// Core post-processing module, already loaded
|
|
91
|
-
continue;
|
|
92
|
-
}
|
|
93
|
-
else {
|
|
94
|
-
try {
|
|
95
|
-
customModules[mod] = await import(pathToFileURL(mod));
|
|
96
|
-
}
|
|
97
|
-
catch (err) {
|
|
98
|
-
throw new Error(`Unknown post-processing module "${mod}"`);
|
|
99
|
-
}
|
|
100
|
-
if (!isModuleValid(customModules[mod])) {
|
|
101
|
-
throw new Error(`"${mod}" is not a valid post-processing module`);
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
else {
|
|
106
|
-
// Given post-processing moduel should already be a good one
|
|
107
|
-
if (!isModuleValid(customModules[mod])) {
|
|
108
|
-
throw new Error(`Post-processing module given as parameter does not have a "run" function`);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
* Returns the post-processing module that match the requested name, or the
|
|
117
|
-
* given parameter if it is a post-processing module already
|
|
118
|
-
*
|
|
119
|
-
* @function
|
|
120
|
-
* @param {String|Object} mod Module name of known post-processing module, or
|
|
121
|
-
* actual post-processing module.
|
|
122
|
-
* @return {Object} Post-processing module
|
|
123
|
-
*/
|
|
124
|
-
function getModule(mod) {
|
|
125
|
-
if (typeof mod === 'string') {
|
|
126
|
-
if (modules[mod]) {
|
|
127
|
-
return Object.assign({ name: mod }, modules[mod]);
|
|
128
|
-
}
|
|
129
|
-
else if (customModules[mod]) {
|
|
130
|
-
return Object.assign({ name: mod }, customModules[mod]);
|
|
131
|
-
}
|
|
132
|
-
else {
|
|
133
|
-
throw new Error(`Unknown post-processing module "${mod}"`);
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
return mod;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* Returns true if given module object looks like a valid module, false
|
|
142
|
-
* otherwise.
|
|
143
|
-
*
|
|
144
|
-
* @function
|
|
145
|
-
* @param {Object} mod Post-processing module object
|
|
146
|
-
* @return {boolean} True when module looks valid, false otherwise
|
|
147
|
-
*/
|
|
148
|
-
function isModuleValid(mod) {
|
|
149
|
-
return !!mod && mod.run && (typeof mod.run === 'function');
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
/**
|
|
154
|
-
* Run a post-processing module against some crawl result
|
|
155
|
-
*
|
|
156
|
-
* @function
|
|
157
|
-
* @param {String|Object} mod Module name for known module or the actual
|
|
158
|
-
* module implementation.
|
|
159
|
-
* @param {Object} crawlResult The entire crawl results if module runs at the
|
|
160
|
-
* "crawl" input level, the result of crawling a spec if module runs at the
|
|
161
|
-
* "spec" input level.
|
|
162
|
-
* @param {Object} options Crawl options. See spec crawler for details.
|
|
163
|
-
* @return {Object} Post-processing structure
|
|
164
|
-
*/
|
|
165
|
-
async function run(mod, crawlResult, options) {
|
|
166
|
-
mod = getModule(mod);
|
|
167
|
-
|
|
168
|
-
if (mod.input === 'crawl') {
|
|
169
|
-
if (crawlResult.crawled || !crawlResult.results) {
|
|
170
|
-
// Post-processing module runs at the crawl level and we received
|
|
171
|
-
// a spec crawl result
|
|
172
|
-
return;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
// TODO: make sure that there is at least one spec for which properties
|
|
176
|
-
// listed in "dependsOn" are set. If not, the module cannot run, which
|
|
177
|
-
// typically signals that the crawler was called with incompatible settings.
|
|
178
|
-
}
|
|
179
|
-
else {
|
|
180
|
-
if (!crawlResult.crawled) {
|
|
181
|
-
// Post-processing module runs at the spec level and we received
|
|
182
|
-
// a full crawl result
|
|
183
|
-
return;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
// TODO: check properties listed in "dependsOn". If none is set, no need to
|
|
187
|
-
// run the module (but not an error per se, it may just be that this
|
|
188
|
-
// particular spec does not define relevant info)
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
return await mod.run(crawlResult, options);
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
/**
|
|
196
|
-
* Save post-processing results
|
|
197
|
-
*
|
|
198
|
-
* @function
|
|
199
|
-
* @param {String|Object} mod Module name for known module or the actual
|
|
200
|
-
* module implementation.
|
|
201
|
-
* @param {Object} processResult The post-processing results
|
|
202
|
-
* @param {Object} options Crawl options. See spec crawler for details.
|
|
203
|
-
* @return {String} Relative path to the file created
|
|
204
|
-
*/
|
|
205
|
-
async function save(mod, processResult, options) {
|
|
206
|
-
mod = getModule(mod);
|
|
207
|
-
processResult = processResult || {};
|
|
208
|
-
options = options || {};
|
|
209
|
-
|
|
210
|
-
if (mod.input === 'crawl') {
|
|
211
|
-
if (processResult.shortname) {
|
|
212
|
-
// Post-processing module runs at the crawl level and we received
|
|
213
|
-
// a spec crawl result
|
|
214
|
-
return;
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
else {
|
|
218
|
-
if (!processResult.shortname) {
|
|
219
|
-
// Post-processing module runs at the spec level and we received
|
|
220
|
-
// a full crawl result
|
|
221
|
-
return;
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
if (!shouldSaveToFile(options)) {
|
|
226
|
-
// Nothing to do if no output folder was given
|
|
227
|
-
return;
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
if (mod.save) {
|
|
231
|
-
// For post-processing modules that have some save logic, we'll just let
|
|
232
|
-
// them do whatever they want
|
|
233
|
-
return mod.save(processResult, options);
|
|
234
|
-
}
|
|
235
|
-
else if (!mod.property) {
|
|
236
|
-
// For post-processing modules that don't touch any single property, default
|
|
237
|
-
// save operation is to do nothing.
|
|
238
|
-
return;
|
|
239
|
-
}
|
|
240
|
-
else if (mod.input === 'crawl') {
|
|
241
|
-
// For post-processing modules that apply at the crawl level, default save
|
|
242
|
-
// operation is to create a JSON file in the output folder named after the
|
|
243
|
-
// post-processing module
|
|
244
|
-
const filename = path.join(options.output, `${mod.property}.json`);
|
|
245
|
-
await createFolderIfNeeded(options.output);
|
|
246
|
-
await fs.promises.writeFile(filename, JSON.stringify(processResult, null, 2), 'utf8');
|
|
247
|
-
return `${mod.property}.json`;
|
|
248
|
-
}
|
|
249
|
-
else {
|
|
250
|
-
// For post-processing modules that apply at the spec level, default save
|
|
251
|
-
// operation is to create a JSON extract file named after the spec's
|
|
252
|
-
// shortname under a subfolder named after the post-processing module in the
|
|
253
|
-
// output folder. Contents of the extract are the contents of the property
|
|
254
|
-
// that has the same name as the module (or the name of the module's
|
|
255
|
-
// "property" parameter if defined) in the post-processing result.
|
|
256
|
-
if (!processResult[mod.property]) {
|
|
257
|
-
return;
|
|
258
|
-
}
|
|
259
|
-
const folder = path.join(options.output, mod.property);
|
|
260
|
-
const filename = path.join(folder, `${processResult.shortname}.json`);
|
|
261
|
-
const contents = {
|
|
262
|
-
spec: {
|
|
263
|
-
title: processResult.title,
|
|
264
|
-
url: processResult.crawled
|
|
265
|
-
}
|
|
266
|
-
};
|
|
267
|
-
contents[mod.property] = processResult[mod.property];
|
|
268
|
-
await createFolderIfNeeded(folder);
|
|
269
|
-
await fs.promises.writeFile(filename, JSON.stringify(contents, null, 2), 'utf8');
|
|
270
|
-
processResult[mod.property] = `${mod.property}/${processResult.shortname}.json`;
|
|
271
|
-
return processResult[mod.property];
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
/**
|
|
277
|
-
* Return true if post-processing module generates extracts per spec series
|
|
278
|
-
*/
|
|
279
|
-
function extractsPerSeries(mod) {
|
|
280
|
-
mod = getModule(mod);
|
|
281
|
-
return (mod.input !== 'crawl') && !!mod.property && !!mod.extractsPerSeries;
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
/**
|
|
286
|
-
* Return true if post-processing module generates extracts per spec series
|
|
287
|
-
*/
|
|
288
|
-
function dependsOn(mod) {
|
|
289
|
-
mod = getModule(mod);
|
|
290
|
-
return mod.dependsOn;
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
/**
|
|
294
|
-
* Return the name of the property that will be set in the spec crawl result
|
|
295
|
-
* when the post-processing module runs, if any
|
|
296
|
-
*/
|
|
297
|
-
function getProperty(mod) {
|
|
298
|
-
mod = getModule(mod);
|
|
299
|
-
return mod.property ?? mod.name;
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
function appliesAtLevel(mod, level) {
|
|
303
|
-
mod = getModule(mod);
|
|
304
|
-
const crawlLevel = mod.input === 'crawl';
|
|
305
|
-
return level === 'crawl' ? crawlLevel : !crawlLevel;
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
/**************************************************
|
|
311
|
-
Export post-processing functions
|
|
312
|
-
**************************************************/
|
|
313
|
-
const postProcessor = {
|
|
314
|
-
modules: Object.keys(modules),
|
|
315
|
-
loadModules,
|
|
316
|
-
run, save,
|
|
317
|
-
extractsPerSeries,
|
|
318
|
-
dependsOn,
|
|
319
|
-
getProperty,
|
|
320
|
-
appliesAtLevel
|
|
321
|
-
}
|
|
322
|
-
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* The post-processor runs post-processing modules against crawl results.
|
|
4
|
+
*
|
|
5
|
+
* There are two types of post-processing modules:
|
|
6
|
+
* 1. Modules that run against the result of crawling an individual spec. Such
|
|
7
|
+
* modules take the spec crawl result as input and typically update it in place
|
|
8
|
+
* 2. Modules that run against an entire crawl result. Such modules take the
|
|
9
|
+
* entire crawl result as input and return whatever structure they would like
|
|
10
|
+
* to return.
|
|
11
|
+
*
|
|
12
|
+
* The post-processor exposes two main functions:
|
|
13
|
+
* - run() to run a post-processing module against crawl results or against a
|
|
14
|
+
* spec crawl result (depending on the module)
|
|
15
|
+
* - save() to save processing results to files
|
|
16
|
+
*
|
|
17
|
+
* A post-processing module needs to expose the following properties and
|
|
18
|
+
* functions:
|
|
19
|
+
* - dependsOn: list of crawl result info that the module depends on. Values
|
|
20
|
+
* include "css", "dfns", "idl", as well as info that other post-processing
|
|
21
|
+
* modules may generate such as "idlparsed".
|
|
22
|
+
* - input: either "crawl" or "spec". Default is "spec". Tells whether the
|
|
23
|
+
* module operates on a spec crawl result or on the entire crawl result
|
|
24
|
+
* - property: When "input" is "spec", gives the name of the property that
|
|
25
|
+
* will be set in the spec crawl result when the post-processing module runs
|
|
26
|
+
* and of the folder that will contain the spec extracts (unless module has its
|
|
27
|
+
* "save" logic). For modules that run at the crawl level, gives the name of
|
|
28
|
+
* the final extract file that gets created (unless module has its own "save"
|
|
29
|
+
* logic).
|
|
30
|
+
* - run: Async function to call to apply the post-processing module. The
|
|
31
|
+
* function is called with either a spec crawl result of the entire crawl result
|
|
32
|
+
* depending on "input". Second parameter is the crawl options object. The
|
|
33
|
+
* function should return the created structure when "input" is "crawl" and
|
|
34
|
+
* the updated spec crawl result when "input" is "spec". Note the function
|
|
35
|
+
* may update the spec crawl result in place.
|
|
36
|
+
* - save: Function to call to save the results of the post-processing module.
|
|
37
|
+
* The function is called with the returned result of running the
|
|
38
|
+
* post-processing module. Second parameter is the crawl options object. The
|
|
39
|
+
* function is only needed if "save" needs to do specific things that the
|
|
40
|
+
* post-processor cannot do on its own. Function must return the relative path
|
|
41
|
+
* to the file that was saved
|
|
42
|
+
* - extractsPerSeries: A boolean flag that tells the crawler that it should
|
|
43
|
+
* clean up extract afterwards to produce extracts per series instead of
|
|
44
|
+
* extracts per spec. The flag is only meaningful if module runs at the spec
|
|
45
|
+
* level and if "property" is set.
|
|
46
|
+
*
|
|
47
|
+
* @module
|
|
48
|
+
*/
|
|
49
|
+
|
|
50
|
+
import fs from 'node:fs';
|
|
51
|
+
import path from 'node:path';
|
|
52
|
+
import { pathToFileURL } from 'node:url';
|
|
53
|
+
import { createFolderIfNeeded, shouldSaveToFile } from './util.js';
|
|
54
|
+
import csscomplete from '../postprocessing/csscomplete.js';
|
|
55
|
+
import cssmerge from '../postprocessing/cssmerge.js';
|
|
56
|
+
import events from '../postprocessing/events.js';
|
|
57
|
+
import idlnames from '../postprocessing/idlnames.js';
|
|
58
|
+
import idlparsed from '../postprocessing/idlparsed.js';
|
|
59
|
+
import annotatelinks from '../postprocessing/annotate-links.js';
|
|
60
|
+
import patchdfns from '../postprocessing/patch-dfns.js';
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Core post-processing modules
|
|
65
|
+
*/
|
|
66
|
+
const modules = {
|
|
67
|
+
csscomplete,
|
|
68
|
+
cssmerge,
|
|
69
|
+
events,
|
|
70
|
+
idlnames,
|
|
71
|
+
idlparsed,
|
|
72
|
+
annotatelinks,
|
|
73
|
+
patchdfns
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Custom post-processing modules
|
|
79
|
+
*/
|
|
80
|
+
const customModules = {};
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Loads post-processing modules once and for all
|
|
85
|
+
*/
|
|
86
|
+
async function loadModules(mods) {
|
|
87
|
+
for (const mod of mods) {
|
|
88
|
+
if (typeof mod === 'string') {
|
|
89
|
+
if (modules[mod]) {
|
|
90
|
+
// Core post-processing module, already loaded
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
try {
|
|
95
|
+
customModules[mod] = await import(pathToFileURL(mod));
|
|
96
|
+
}
|
|
97
|
+
catch (err) {
|
|
98
|
+
throw new Error(`Unknown post-processing module "${mod}"`);
|
|
99
|
+
}
|
|
100
|
+
if (!isModuleValid(customModules[mod])) {
|
|
101
|
+
throw new Error(`"${mod}" is not a valid post-processing module`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
// Given post-processing moduel should already be a good one
|
|
107
|
+
if (!isModuleValid(customModules[mod])) {
|
|
108
|
+
throw new Error(`Post-processing module given as parameter does not have a "run" function`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Returns the post-processing module that match the requested name, or the
|
|
117
|
+
* given parameter if it is a post-processing module already
|
|
118
|
+
*
|
|
119
|
+
* @function
|
|
120
|
+
* @param {String|Object} mod Module name of known post-processing module, or
|
|
121
|
+
* actual post-processing module.
|
|
122
|
+
* @return {Object} Post-processing module
|
|
123
|
+
*/
|
|
124
|
+
function getModule(mod) {
|
|
125
|
+
if (typeof mod === 'string') {
|
|
126
|
+
if (modules[mod]) {
|
|
127
|
+
return Object.assign({ name: mod }, modules[mod]);
|
|
128
|
+
}
|
|
129
|
+
else if (customModules[mod]) {
|
|
130
|
+
return Object.assign({ name: mod }, customModules[mod]);
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
throw new Error(`Unknown post-processing module "${mod}"`);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return mod;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Returns true if given module object looks like a valid module, false
|
|
142
|
+
* otherwise.
|
|
143
|
+
*
|
|
144
|
+
* @function
|
|
145
|
+
* @param {Object} mod Post-processing module object
|
|
146
|
+
* @return {boolean} True when module looks valid, false otherwise
|
|
147
|
+
*/
|
|
148
|
+
function isModuleValid(mod) {
|
|
149
|
+
return !!mod && mod.run && (typeof mod.run === 'function');
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Run a post-processing module against some crawl result
|
|
155
|
+
*
|
|
156
|
+
* @function
|
|
157
|
+
* @param {String|Object} mod Module name for known module or the actual
|
|
158
|
+
* module implementation.
|
|
159
|
+
* @param {Object} crawlResult The entire crawl results if module runs at the
|
|
160
|
+
* "crawl" input level, the result of crawling a spec if module runs at the
|
|
161
|
+
* "spec" input level.
|
|
162
|
+
* @param {Object} options Crawl options. See spec crawler for details.
|
|
163
|
+
* @return {Object} Post-processing structure
|
|
164
|
+
*/
|
|
165
|
+
async function run(mod, crawlResult, options) {
|
|
166
|
+
mod = getModule(mod);
|
|
167
|
+
|
|
168
|
+
if (mod.input === 'crawl') {
|
|
169
|
+
if (crawlResult.crawled || !crawlResult.results) {
|
|
170
|
+
// Post-processing module runs at the crawl level and we received
|
|
171
|
+
// a spec crawl result
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// TODO: make sure that there is at least one spec for which properties
|
|
176
|
+
// listed in "dependsOn" are set. If not, the module cannot run, which
|
|
177
|
+
// typically signals that the crawler was called with incompatible settings.
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
if (!crawlResult.crawled) {
|
|
181
|
+
// Post-processing module runs at the spec level and we received
|
|
182
|
+
// a full crawl result
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// TODO: check properties listed in "dependsOn". If none is set, no need to
|
|
187
|
+
// run the module (but not an error per se, it may just be that this
|
|
188
|
+
// particular spec does not define relevant info)
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
return await mod.run(crawlResult, options);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Save post-processing results
|
|
197
|
+
*
|
|
198
|
+
* @function
|
|
199
|
+
* @param {String|Object} mod Module name for known module or the actual
|
|
200
|
+
* module implementation.
|
|
201
|
+
* @param {Object} processResult The post-processing results
|
|
202
|
+
* @param {Object} options Crawl options. See spec crawler for details.
|
|
203
|
+
* @return {String} Relative path to the file created
|
|
204
|
+
*/
|
|
205
|
+
async function save(mod, processResult, options) {
|
|
206
|
+
mod = getModule(mod);
|
|
207
|
+
processResult = processResult || {};
|
|
208
|
+
options = options || {};
|
|
209
|
+
|
|
210
|
+
if (mod.input === 'crawl') {
|
|
211
|
+
if (processResult.shortname) {
|
|
212
|
+
// Post-processing module runs at the crawl level and we received
|
|
213
|
+
// a spec crawl result
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
else {
|
|
218
|
+
if (!processResult.shortname) {
|
|
219
|
+
// Post-processing module runs at the spec level and we received
|
|
220
|
+
// a full crawl result
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
if (!shouldSaveToFile(options)) {
|
|
226
|
+
// Nothing to do if no output folder was given
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
if (mod.save) {
|
|
231
|
+
// For post-processing modules that have some save logic, we'll just let
|
|
232
|
+
// them do whatever they want
|
|
233
|
+
return mod.save(processResult, options);
|
|
234
|
+
}
|
|
235
|
+
else if (!mod.property) {
|
|
236
|
+
// For post-processing modules that don't touch any single property, default
|
|
237
|
+
// save operation is to do nothing.
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
else if (mod.input === 'crawl') {
|
|
241
|
+
// For post-processing modules that apply at the crawl level, default save
|
|
242
|
+
// operation is to create a JSON file in the output folder named after the
|
|
243
|
+
// post-processing module
|
|
244
|
+
const filename = path.join(options.output, `${mod.property}.json`);
|
|
245
|
+
await createFolderIfNeeded(options.output);
|
|
246
|
+
await fs.promises.writeFile(filename, JSON.stringify(processResult, null, 2), 'utf8');
|
|
247
|
+
return `${mod.property}.json`;
|
|
248
|
+
}
|
|
249
|
+
else {
|
|
250
|
+
// For post-processing modules that apply at the spec level, default save
|
|
251
|
+
// operation is to create a JSON extract file named after the spec's
|
|
252
|
+
// shortname under a subfolder named after the post-processing module in the
|
|
253
|
+
// output folder. Contents of the extract are the contents of the property
|
|
254
|
+
// that has the same name as the module (or the name of the module's
|
|
255
|
+
// "property" parameter if defined) in the post-processing result.
|
|
256
|
+
if (!processResult[mod.property]) {
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
const folder = path.join(options.output, mod.property);
|
|
260
|
+
const filename = path.join(folder, `${processResult.shortname}.json`);
|
|
261
|
+
const contents = {
|
|
262
|
+
spec: {
|
|
263
|
+
title: processResult.title,
|
|
264
|
+
url: processResult.crawled
|
|
265
|
+
}
|
|
266
|
+
};
|
|
267
|
+
contents[mod.property] = processResult[mod.property];
|
|
268
|
+
await createFolderIfNeeded(folder);
|
|
269
|
+
await fs.promises.writeFile(filename, JSON.stringify(contents, null, 2), 'utf8');
|
|
270
|
+
processResult[mod.property] = `${mod.property}/${processResult.shortname}.json`;
|
|
271
|
+
return processResult[mod.property];
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Return true if post-processing module generates extracts per spec series
|
|
278
|
+
*/
|
|
279
|
+
function extractsPerSeries(mod) {
|
|
280
|
+
mod = getModule(mod);
|
|
281
|
+
return (mod.input !== 'crawl') && !!mod.property && !!mod.extractsPerSeries;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Return true if post-processing module generates extracts per spec series
|
|
287
|
+
*/
|
|
288
|
+
function dependsOn(mod) {
|
|
289
|
+
mod = getModule(mod);
|
|
290
|
+
return mod.dependsOn;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Return the name of the property that will be set in the spec crawl result
|
|
295
|
+
* when the post-processing module runs, if any
|
|
296
|
+
*/
|
|
297
|
+
function getProperty(mod) {
|
|
298
|
+
mod = getModule(mod);
|
|
299
|
+
return mod.property ?? mod.name;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
function appliesAtLevel(mod, level) {
|
|
303
|
+
mod = getModule(mod);
|
|
304
|
+
const crawlLevel = mod.input === 'crawl';
|
|
305
|
+
return level === 'crawl' ? crawlLevel : !crawlLevel;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
/**************************************************
|
|
311
|
+
Export post-processing functions
|
|
312
|
+
**************************************************/
|
|
313
|
+
const postProcessor = {
|
|
314
|
+
modules: Object.keys(modules),
|
|
315
|
+
loadModules,
|
|
316
|
+
run, save,
|
|
317
|
+
extractsPerSeries,
|
|
318
|
+
dependsOn,
|
|
319
|
+
getProperty,
|
|
320
|
+
appliesAtLevel
|
|
321
|
+
}
|
|
322
|
+
|
|
323
323
|
export default postProcessor;
|