Skip to content

Commit

Permalink
Add --sort option to CLI (#678)
Browse files Browse the repository at this point in the history
Specs are sorted per URL in browser-specs. That order is not fantastic
when preparing a human-readable report such as the one in:
#663

The --sort option lets makes it possible to specify the order to follow
at each level of the structured report: one of "default", "name" or
"title". We may want to add additional possibilities over time.
  • Loading branch information
tidoust authored Aug 26, 2024
1 parent beeafd1 commit 785e2c3
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 3 deletions.
24 changes: 21 additions & 3 deletions src/lib/study.js
Original file line number Diff line number Diff line change
Expand Up @@ -241,9 +241,11 @@ function getAnomalyGroupFromType(type) {
/**
* Structure a flat list of anomalies to the requested structure
*/
function structureResults(structure, anomalies, crawlResults) {
function structureResults(structure, sort, anomalies, crawlResults) {
const levels = structure.split('/')
.map(level => level.replace(/\s+/g, ''));
const sortKeys = sort.split('/')
.map(level => level.replace(/\s+/g, ''));
const report = [];

switch (levels[0]) {
Expand Down Expand Up @@ -348,10 +350,25 @@ function structureResults(structure, anomalies, crawlResults) {
break;
}

switch (sortKeys[0] ?? 'default') {
case 'name':
report.sort((e1, e2) => e1.name.localeCompare(e2.name));
break;
case 'title':
// Note: for actual anomalies, the title is the anomaly message. All
// other entries have title.
report.sort((e1, e2) => (e1.title ?? e1.message).localeCompare(e2.title ?? e2.message));
break;
case 'default':
default:
break;
}

if (levels.length > 1) {
const itemsStructure = levels.slice(1).join('/');
const itemsSort = sortKeys.slice(1).join('/');
for (const entry of report) {
entry.items = structureResults(itemsStructure, entry.anomalies, crawlResults);
entry.items = structureResults(itemsStructure, itemsSort, entry.anomalies, crawlResults);
delete entry.anomalies;
}
}
Expand Down Expand Up @@ -556,6 +573,7 @@ export default async function study(specs, options = {}) {

const what = options.what ?? ['all'];
const structure = options.structure ?? 'type + spec';
const sort = options.sort ?? 'default';
const format = options.format ?? 'issue';

if (!what.includes('all')) {
Expand Down Expand Up @@ -600,7 +618,7 @@ export default async function study(specs, options = {}) {

// Now that we have a flat report of anomalies,
// let's structure and serialize it as requested
const report = structureResults(structure, anomalies, options.crawlResults);
const report = structureResults(structure, sort, anomalies, options.crawlResults);

// And serialize it using the right format
const result = {
Expand Down
35 changes: 35 additions & 0 deletions strudy.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ program
.option('-i, --issues <folder>', 'report issues as markdown files in the given folder')
.option('-m, --max <max>', 'maximum number of issue files to create/update', myParseInt, 0)
.option('-s, --spec <specs...>', 'restrict analysis to given specs')
.option('--sort <sort>', 'key(s) to use to sort the structured report', 'default')
.option('--structure <structure>', 'report structure', 'type+spec')
.option('--tr <trreport>', 'path/URL to crawl report on published specs')
.option('--update-mode <mode>', 'what issue files to update', 'new')
Expand Down Expand Up @@ -136,6 +137,39 @@ Usage notes for some of the options:
For instance:
$ strudy inspect . --spec picture-in-picture https://w3c.github.io/mediasession/
--sort <sort>
Specifies the key(s) to use to sort each level in the structured report.
Use "/" to separate levels. See --structure for details on the possible
report structure.
Possible keys:
"default" follow the natural order of the underlying structures, e.g.
return specs in the order in which they appear in the initial
list, anomalies in extraction order (which usually follows the
document order)
"name" sort entries by the name. For a "spec" level, the name is the
spec's shortname. For a "type" level, the name is the anomaly
type name. For a "type+spec" level, the name is the name of the
file that would be created if --issues is set, meaning the spec's
shortname completed with the anomaly type name.
"title" sort entries by their title. For a "spec" level, the title is the
spec's title. For the final level, the title is the anomaly
message. Etc.
If the --sort value contains more levels than there are in the structured
report, additional keys are ignored. If the value contails fewer levels than
there are in the structured report, the default order is used for unspecified
levels.
For example, if the structure is "type/spec", the --sort option could be:
"default" to use the default order at all levels
"default/title" to use the default order for the root level, and to sort
specs by title
"name/title/title" to sort anomaly types by names, specs by title, and
anomalies by message.
Sort is always ascending.
--structure <type>
Describes the hierarchy in the report(s) that Strudy returns. Possible values:
"flat" no level, report anomalies one by one
Expand Down Expand Up @@ -257,6 +291,7 @@ Format must be one of "json" or "markdown".`)
const anomaliesReport = await study(edReport.results, {
what: options.what,
structure: options.structure,
sort: options.sort,
format: options.format === 'json' ?
'json' :
(options.issues ? 'issue' : 'full'),
Expand Down
18 changes: 18 additions & 0 deletions test/study.js
Original file line number Diff line number Diff line change
Expand Up @@ -191,4 +191,22 @@ describe('The main study function', function () {
See [Dealing with the event loop](https://html.spec.whatwg.org/multipage/webappapis.html#event-loop-for-spec-authors) in the HTML specification for guidance on how to deal with algorithm sections that run *in parallel*.`
});
});

it('sorts entries as requested in the final report', async function() {
const crawlResult = [
populateSpec(specUrl, { error: 'Boo' }),
populateSpec(specUrl2, { error: 'Borked' })
];
const report = await study(crawlResult, { structure: 'type/spec', sort: 'default/title', htmlFragments: {} });
assertNbAnomalies(report.results, 1);
assertAnomaly(report.results, 0, {
title: 'Crawl error',
content:
`The following crawl errors occurred:
* [Hello universe API](https://w3c.github.io/universe/)
* [ ] Borked
* [Hello world API](https://w3c.github.io/world/)
* [ ] Boo`
});
});
});

0 comments on commit 785e2c3

Please sign in to comment.