Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Only emit APIs that are standards track and not experimental #239

Merged
merged 6 commits into from
May 21, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 83 additions & 13 deletions tool/generator/bcd.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@ import 'filesystem_api.dart';
/// property status (standards track, experimental, deprecated) and supported
/// browser (chrome, safari, firefox) info.
class BrowserCompatData {
static final _eventHandlers = <String, Set<BCDPropertyStatus>>{};
srujzs marked this conversation as resolved.
Show resolved Hide resolved

/// Returns whether [name] is an event handler that is supported in any
/// interface.
static bool isEventHandlerSupported(String name) =>
_eventHandlers[name]?.any((bcd) => bcd.shouldGenerate) == true;

static BrowserCompatData read() {
final path =
p.join('node_modules', '@mdn', 'browser-compat-data', 'data.json');
Expand All @@ -22,10 +29,48 @@ class BrowserCompatData {
) as JSString)
.toDart;

final api = (jsonDecode(content) as Map)['api'] as Map<String, dynamic>;
final interfaces = api.symbolNames
.map((key) => BCDInterfaceStatus(key, api[key] as Map<String, dynamic>))
.toList();
final contentMap = jsonDecode(content) as Map;
final api = contentMap['api'] as Map<String, dynamic>;
// MDN files WebAssembly compat data in a separate folder, so we need to
// unify.
final webassembly = (contentMap['webassembly']
as Map<String, dynamic>)['api'] as Map<String, dynamic>;
api.addAll(webassembly);
// Add info for the namespace as well.
api['WebAssembly'] = webassembly;

final interfaces = <BCDInterfaceStatus>{};
final globals = <String, Map<String, dynamic>>{};
final globalInterfaces = <BCDInterfaceStatus>{};
const globalsFilePrefix = 'api/_globals';

for (final symbolName in api.symbolNames) {
final apiInfo = api[symbolName] as Map<String, dynamic>;
final interface = BCDInterfaceStatus(symbolName, apiInfo);
if (interface._sourceFile.startsWith(globalsFilePrefix)) {
// MDN stores global members e.g. `isSecureContext` in the same location
// as the interfaces. These are not interfaces, but rather properties
// that should go in `Window` and `WorkerGlobalScope`. We cache the
// compat data and add them directly to the relevant interfaces later.
// https://github.com/mdn/browser-compat-data/blob/main/docs/data-guidelines/api.md#global-apis
globals[symbolName] = apiInfo;
// The compat data for the console namespace is within this property. It
// should be exposed both as a global and as a namespace.
if (symbolName == 'console') interfaces.add(interface);
} else {
interfaces.add(interface);
}
if (symbolName == 'Window' || symbolName == 'WorkerGlobalScope') {
globalInterfaces.add(interface);
}
}

globals.forEach((name, apiInfo) {
for (final globalInterface in globalInterfaces) {
globalInterface.addProperty(name, apiInfo);
}
});

return BrowserCompatData(Map.fromIterable(
interfaces,
key: (i) => (i as BCDInterfaceStatus).name,
Expand All @@ -37,29 +82,53 @@ class BrowserCompatData {
BrowserCompatData(this.interfaces);

BCDInterfaceStatus? retrieveInterfaceFor(String name) => interfaces[name];

bool shouldGenerateInterface(String name) =>
retrieveInterfaceFor(name)?.shouldGenerate ?? false;
}

class BCDInterfaceStatus extends BCDItem {
late final Map<String, BCDPropertyStatus> properties;
final _properties = <String, BCDPropertyStatus>{};
srujzs marked this conversation as resolved.
Show resolved Hide resolved

BCDInterfaceStatus(super.name, super.json) {
properties = Map.fromIterable(
json.symbolNames,
value: (name) => BCDPropertyStatus(
name as String, json[name] as Map<String, dynamic>, this),
);
for (final symbolName in json.symbolNames) {
addProperty(symbolName, json[symbolName] as Map<String, dynamic>);
}
}

void addProperty(String property, Map<String, dynamic> compat) {
// Event compatibility data is stored as `<name_of_event>_event`. In order
// to have compatibility data for `onX` properties, we need to replace such
// property names. See https://github.com/mdn/browser-compat-data/blob/main/docs/data-guidelines/api.md#dom-events-eventname_event
// for more details.
late BCDPropertyStatus status;
const eventSuffix = '_event';
if (property.endsWith(eventSuffix)) {
property = 'on${property.replaceAll(eventSuffix, '')}';
srujzs marked this conversation as resolved.
Show resolved Hide resolved
status = BCDPropertyStatus(property, compat, this);
BrowserCompatData._eventHandlers
.putIfAbsent(property, () => {})
.add(status);
} else {
status = BCDPropertyStatus(property, compat, this);
}
_properties[property] = status;
}

BCDPropertyStatus? retrievePropertyFor(String name) => properties[name];
BCDPropertyStatus? retrievePropertyFor(String name, {bool isStatic = false}) {
if (isStatic) name = '${name}_static';
return _properties[name];
}

bool get shouldGenerate =>
standardTrack && chromeSupported && firefoxSupported && safariSupported;
bool get shouldGenerate => standardTrack && !experimental;
}

class BCDPropertyStatus extends BCDItem {
final BCDInterfaceStatus parent;

BCDPropertyStatus(super.name, super.json, this.parent);

bool get shouldGenerate => standardTrack && !experimental;
}

abstract class BCDItem {
Expand All @@ -69,6 +138,7 @@ abstract class BCDItem {
BCDItem(this.name, this.json);

Map<String, dynamic> get _compat => json['__compat'] as Map<String, dynamic>;
String get _sourceFile => _compat['source_file'] as String;
Map<String, dynamic> get _status => _compat['status'] as Map<String, dynamic>;
Map<String, dynamic> get _support =>
_compat['support'] as Map<String, dynamic>;
Expand Down
2 changes: 1 addition & 1 deletion tool/generator/generate_bindings.dart
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,6 @@ Future<TranslationResult> generateBindings(
final ast = entry[1] as JSArray<webidl.Node>;
translator.collect(shortname, ast);
}
translator.setOrUpdateInterfacelikes();
translator.setOrUpdateInterfacesAndNamespaces();
return translator.translate();
}
Loading