Skip to content

Commit

Permalink
Add a script to generate a draft feature per spec (#1195)
Browse files Browse the repository at this point in the history
One of the features, the Vibration API, is added to show what this will
look like.
  • Loading branch information
foolip authored Jun 28, 2024
1 parent 705f6a6 commit f7ec95a
Show file tree
Hide file tree
Showing 5 changed files with 139 additions and 1 deletion.
18 changes: 18 additions & 0 deletions features/draft/spec/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Draft spec features

This directory is for draft features organized by spec. These features require
review before being added to web-features, as most specs define more than one
feature and many features span specs.

To help out, pick a feature and do the following:

- Follow the spec link and make a judgment whether it's reasonable to describe
this as a single features or if needs to be split up.
- Review `baseline_low_date`, does it look plausible? If not, remove features
from `compat_features` until the date and browser versions seem plausible. Run
`npm run dist features/draft/spec` to regenerate dist.
- Write a description for the feature.
- Move the file into the main features/ directory and submit a PR with your
changes.

Happy YAMLing!
6 changes: 6 additions & 0 deletions features/draft/spec/vibration.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
draft_date: 2024-06-07
name: Vibration API (Second Edition)
description: TODO
spec: https://w3c.github.io/vibration/
compat_features:
- api.Navigator.vibrate
10 changes: 10 additions & 0 deletions features/draft/spec/vibration.yml.dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Generated from: vibration.yml
# Do not edit this file by hand. Edit the source file instead!

status:
baseline: false
support:
chrome: "32"
chrome_android: "32"
edge: "79"
firefox: "16"
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@
"test:format": "prettier --check .",
"test:coverage": "npm run --workspaces test:coverage",
"format": "npx prettier --write .",
"feature-init": "tsx scripts/feature-init.ts"
"feature-init": "tsx scripts/feature-init.ts",
"update-drafts": "tsx scripts/update-drafts.ts"
},
"devDependencies": {
"@js-temporal/polyfill": "^0.4.4",
Expand Down
103 changes: 103 additions & 0 deletions scripts/update-drafts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import { Compat } from "compute-baseline/browser-compat-data";
import fs from "node:fs/promises";
import { fileURLToPath } from "node:url";
import YAML from "yaml";
import webSpecs from 'web-specs' assert { type: 'json' };
import features from '../index.js';

function* getPages(spec): Generator<string> {
yield spec.url;
if (spec.nightly?.url) {
yield spec.nightly.url;
}
if (spec.nightly?.pages) {
yield* spec.nightly.pages;
}
}

function normalize(page: string) {
const url = new URL(page);
// Remove any fragment.
url.hash = '';
// Collapse HTML and ECMA-262 multipage into a single canonical page.
const multipageIndex = url.pathname.indexOf('/multipage/');
if (multipageIndex !== -1) {
url.pathname = url.pathname.substring(0, multipageIndex + 1);
}
// Strip levels from CSS specs.
if (url.hostname.startsWith('drafts.')) {
url.pathname = url.pathname.replace(/-\d+\/$/, '/');
}
return String(url);
}

async function main() {
const compat = new Compat();

// Build a set of used BCD keys.
const usedFeatures = new Set<string>(
Object.values(features).flatMap((data) => data.compat_features)
);

// Build a map from URLs to spec.
const pageToSpec = new Map<string, object>();
for (const spec of webSpecs) {
for (const page of getPages(spec)) {
pageToSpec.set(normalize(page), spec);
}
}

// Iterate BCD and group compat features by spec.
const specToCompatFeatures = new Map<object, Set<string>>();
for (const feature of compat.walk()) {
// Skip any BCD keys already used in web-features.
if (usedFeatures.has(feature.id)) {
continue;
}

// Skip deprecated and non-standard features.
const status = feature.data.__compat.status;
if (status?.deprecated || !status?.standard_track) {
continue;
}

const spec_url = feature.data.__compat.spec_url;
if (!spec_url) {
continue;
}

const urls = Array.isArray(spec_url) ? spec_url : [spec_url];
for (const url of urls) {
const spec = pageToSpec.get(normalize(url));
if (!spec) {
console.warn(`${url} not matched to any spec`);
continue;
}
const keys = specToCompatFeatures.get(spec);
if (keys) {
keys.add(feature.id);
} else {
specToCompatFeatures.set(spec, new Set([feature.id]));
}
}
}

for (const [spec, compatFeatures] of specToCompatFeatures.entries()) {
// Write out draft feature per spec.
const id = spec.shortname;

const feature = {
draft_date: new Date().toISOString().substring(0, 10),
name: spec.title,
description: 'TODO',
spec: spec.nightly?.url ?? spec.url,
compat_features: Array.from(compatFeatures).sort(),
};
const yaml = YAML.stringify(feature);
await fs.writeFile(`features/draft/spec/${id}.yml`, yaml);
}
}

if (process.argv[1] === fileURLToPath(import.meta.url)) {
await main();
}

0 comments on commit f7ec95a

Please sign in to comment.