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

Add a generate-all flag to emit all bindings #302

Merged
merged 2 commits into from
Sep 13, 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
86 changes: 86 additions & 0 deletions .github/workflows/dart.yml
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,90 @@ jobs:
- job_008
- job_009
job_012:
name: "generate_all_and_analyze; Dart dev; PKG: web_generator; `dart analyze --fatal-infos .`"
runs-on: ubuntu-latest
steps:
- name: Cache Pub hosted dependencies
uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9
with:
path: "~/.pub-cache/hosted"
key: "os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:web_generator;commands:analyze"
restore-keys: |
os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:web_generator
os:ubuntu-latest;pub-cache-hosted;sdk:dev
os:ubuntu-latest;pub-cache-hosted
os:ubuntu-latest
- name: Setup Dart SDK
uses: dart-lang/setup-dart@0a8a0fc875eb934c15d08629302413c671d3f672
with:
sdk: dev
- id: checkout
name: Checkout repository
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332
- id: web_generator_pub_upgrade
name: web_generator; dart pub upgrade
run: dart pub upgrade
if: "always() && steps.checkout.conclusion == 'success'"
working-directory: web_generator
- name: "web_generator; dart analyze --fatal-infos ."
run: dart analyze --fatal-infos .
if: "always() && steps.web_generator_pub_upgrade.conclusion == 'success'"
working-directory: web_generator
needs:
- job_001
- job_002
- job_003
- job_004
- job_005
- job_006
- job_007
- job_008
- job_009
- job_010
- job_011
job_013:
name: "generate_all_and_analyze; Dart dev; PKG: web_generator; `dart bin/update_bindings.dart --generate-all`"
runs-on: ubuntu-latest
steps:
- name: Cache Pub hosted dependencies
uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9
with:
path: "~/.pub-cache/hosted"
key: "os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:web_generator;commands:command_2"
restore-keys: |
os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:web_generator
os:ubuntu-latest;pub-cache-hosted;sdk:dev
os:ubuntu-latest;pub-cache-hosted
os:ubuntu-latest
- name: Setup Dart SDK
uses: dart-lang/setup-dart@0a8a0fc875eb934c15d08629302413c671d3f672
with:
sdk: dev
- id: checkout
name: Checkout repository
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332
- id: web_generator_pub_upgrade
name: web_generator; dart pub upgrade
run: dart pub upgrade
if: "always() && steps.checkout.conclusion == 'success'"
working-directory: web_generator
- name: "web_generator; dart bin/update_bindings.dart --generate-all"
run: dart bin/update_bindings.dart --generate-all
if: "always() && steps.web_generator_pub_upgrade.conclusion == 'success'"
working-directory: web_generator
needs:
- job_001
- job_002
- job_003
- job_004
- job_005
- job_006
- job_007
- job_008
- job_009
- job_010
- job_011
job_014:
name: "dart_fixes; Dart main; PKG: web; `dart fix --compare-to-golden test_fixes`"
runs-on: ubuntu-latest
steps:
Expand Down Expand Up @@ -461,3 +545,5 @@ jobs:
- job_009
- job_010
- job_011
- job_012
- job_013
1 change: 1 addition & 0 deletions mono_repo.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ merge_stages:
- unit_test
- dart_fixes
- generate_and_analyze
- generate_all_and_analyze
4 changes: 4 additions & 0 deletions tool/ci.sh
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,10 @@ for PKG in ${PKGS}; do
echo 'dart bin/update_bindings.dart'
dart bin/update_bindings.dart || EXIT_CODE=$?
;;
command_2)
echo 'dart bin/update_bindings.dart --generate-all'
dart bin/update_bindings.dart --generate-all || EXIT_CODE=$?
;;
format)
echo 'dart format --output=none --set-exit-if-changed .'
dart format --output=none --set-exit-if-changed . || EXIT_CODE=$?
Expand Down
8 changes: 4 additions & 4 deletions web_generator/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
- Initial separation of `web_generator` from `web`.
- New IDL interface `RHL` added. `ExtendedAttribute` idl interface updated to
expose its `rhs` property and `Interfacelike` idl interface updated to expose
`extAttrs` property. The generator now adds a
`extAttrs` property. The generator now adds a
`JS(LegacyNamespace.$extensionTypeName)` annotation on `JS` objects if
they've an IDL extended attribute `[LegacyNamespace=Foo]` defined in their IDL
description.


description.
- Added `--generate-all` option to generate all bindings, including experimental
and non-standard APIs.
11 changes: 11 additions & 0 deletions web_generator/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,17 @@ definitions:
emit code that is standards track and is not experimental to reduce the number
of breaking changes.

## Generate all bindings

To ignore the compatibility data and emit all members, run:

```shell
dart bin/update_bindings.dart --generate-all
```

This is useful if you want to avoid having to write bindings manually for some
experimental and non-standard APIs.

## Web IDL versions

Based on:
Expand Down
13 changes: 11 additions & 2 deletions web_generator/bin/update_bindings.dart
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,14 @@ $_usage''');
};

// Run app with `node`.
final generateAll = argResult['generate-all'] as bool;
await _runProc(
'node',
['main.mjs', Platform.script.resolve('../../web/lib/src').path],
[
'main.mjs',
'--output-directory=${Platform.script.resolve('../../web/lib/src').path}',
if (generateAll) '--generate-all',
],
workingDirectory: _bindingsGeneratorPath,
);

Expand Down Expand Up @@ -232,4 +237,8 @@ ${_parser.usage}''';
final _parser = ArgParser()
..addFlag('update', abbr: 'u', help: 'Update npm dependencies')
..addFlag('compile', defaultsTo: true)
..addFlag('help', negatable: false);
..addFlag('help', negatable: false)
..addFlag('generate-all',
negatable: false,
help: 'Generate bindings for all IDL definitions, including experimental '
'and non-standard APIs.');
16 changes: 12 additions & 4 deletions web_generator/lib/src/bcd.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,18 @@ import 'filesystem_api.dart';
class BrowserCompatData {
static final Map<String, Set<BCDPropertyStatus>> _eventHandlers = {};

/// Whether to generate all the bindings regardless of property status.
static bool generateAll = false;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was trying to see if we could get away without making this static and without too much refactoring, and it appears that maybe it's possible?

Seems we use this property in:

  • BCDItem subclasses's shouldGenerate getters: those however appear to be used within the context of a method that already checks for generateAll (isEventHandlerSupported and shouldGenerateInterface) so it may be safe to remove the use from these getters?
  • the methods where generateAll is used also have access to a translator, so they can fetch the value through it (e.g. _shouldGenerateMember can read it from Translator.instance!.browserCompatibilityData.generateAll?

Would that work?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea! It took a little bit of refactoring, but making shouldGenerate a field allows this to work for the first bullet-point and the second bullet point works for translator.dart. isEventHandlerSupported doesn't need to check for generateAll since shouldGenerate handles that anyways.


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

static BrowserCompatData read() {
static BrowserCompatData read({required bool generateAll}) {
BrowserCompatData.generateAll = generateAll;

final path =
p.join('node_modules', '@mdn', 'browser-compat-data', 'data.json');
final content = (fs.readFileSync(
Expand Down Expand Up @@ -84,7 +90,7 @@ class BrowserCompatData {
BCDInterfaceStatus? retrieveInterfaceFor(String name) => interfaces[name];

bool shouldGenerateInterface(String name) =>
retrieveInterfaceFor(name)?.shouldGenerate ?? false;
generateAll || (retrieveInterfaceFor(name)?.shouldGenerate ?? false);
srujzs marked this conversation as resolved.
Show resolved Hide resolved
}

class BCDInterfaceStatus extends BCDItem {
Expand Down Expand Up @@ -120,15 +126,17 @@ class BCDInterfaceStatus extends BCDItem {
return _properties[name];
}

bool get shouldGenerate => standardTrack && !experimental;
bool get shouldGenerate =>
BrowserCompatData.generateAll || (standardTrack && !experimental);
}

class BCDPropertyStatus extends BCDItem {
final BCDInterfaceStatus parent;

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

bool get shouldGenerate => standardTrack && !experimental;
bool get shouldGenerate =>
BrowserCompatData.generateAll || (standardTrack && !experimental);
}

abstract class BCDItem {
Expand Down
25 changes: 20 additions & 5 deletions web_generator/lib/src/dart_main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import 'dart:js_interop';

import 'package:args/args.dart';
import 'package:code_builder/code_builder.dart' as code;
import 'package:dart_style/dart_style.dart';

Expand All @@ -18,21 +19,27 @@ import 'util.dart';
// probably involve parsing the TC39 spec.

void main(List<String> args) async {
await _generateAndWriteBindings(args[0]);
final ArgResults argResult;
argResult = _parser.parse(args);
await _generateAndWriteBindings(
outputDirectory: argResult['output-directory'] as String,
generateAll: argResult['generate-all'] as bool);
}

Future<void> _generateAndWriteBindings(String dir) async {
Future<void> _generateAndWriteBindings(
{required String outputDirectory, required bool generateAll}) async {
const librarySubDir = 'dom';

ensureDirectoryExists('$dir/$librarySubDir');
ensureDirectoryExists('$outputDirectory/$librarySubDir');

final bindings = await generateBindings(packageRoot, librarySubDir);
final bindings = await generateBindings(packageRoot, librarySubDir,
generateAll: generateAll);
for (var entry in bindings.entries) {
final libraryPath = entry.key;
final library = entry.value;

final contents = _emitLibrary(library).toJS;
fs.writeFileSync('$dir/$libraryPath'.toJS, contents);
fs.writeFileSync('$outputDirectory/$libraryPath'.toJS, contents);
}
}

Expand All @@ -47,3 +54,11 @@ String _emitLibrary(code.Library library) {
return DartFormatter(languageVersion: DartFormatter.latestLanguageVersion)
.format(source.toString());
}

final _parser = ArgParser()
..addOption('output-directory',
mandatory: true, help: 'Directory where bindings will be generated to.')
..addFlag('generate-all',
negatable: false,
help: 'Generate bindings for all IDL definitions, including experimental '
'and non-standard APIs.');
6 changes: 4 additions & 2 deletions web_generator/lib/src/generate_bindings.dart
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,13 @@ Future<Map<String, Set<String>>> _generateElementTagMap() async {
}

Future<TranslationResult> generateBindings(
String packageRoot, String librarySubDir) async {
String packageRoot, String librarySubDir,
{required bool generateAll}) async {
final cssStyleDeclarations = await _generateCSSStyleDeclarations();
final elementHTMLMap = await _generateElementTagMap();
final translator = Translator(
packageRoot, librarySubDir, cssStyleDeclarations, elementHTMLMap);
packageRoot, librarySubDir, cssStyleDeclarations, elementHTMLMap,
generateAll: generateAll);
final array = objectEntries(await idl.parseAll().toDart);
for (var i = 0; i < array.length; i++) {
final entry = array[i] as JSArray<JSAny?>;
Expand Down
4 changes: 2 additions & 2 deletions web_generator/lib/src/main.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ globalThis.idl = idl;
globalThis.location = { href: `file://${process.cwd()}/` }

globalThis.dartMainRunner = async function (main, args) {
const dir = process.argv[2];
await main(dir);
const dartArgs = process.argv.slice(2);
await main(dartArgs);
}

async function scriptMain() {
Expand Down
28 changes: 15 additions & 13 deletions web_generator/lib/src/translator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -522,7 +522,7 @@ class _PartialInterfacelike {
// TODO(srujzs): Should we handle other special operations,
// unnamed or otherwise? For now, don't emit the unnamed ones and
// do nothing special for the named ones.
if (operationName.isEmpty) break;
if (operationName.isEmpty) continue;
}
final isStatic = operation.special == 'static';
if (shouldQueryMDN &&
Expand Down Expand Up @@ -591,6 +591,7 @@ class _PartialInterfacelike {
/// Given a [memberName] and whether it [isStatic], return whether it is a
/// member that should be emitted according to the compat data.
bool _shouldGenerateMember(String memberName, {bool isStatic = false}) {
if (BrowserCompatData.generateAll) return true;
// Compat data only exists for interfaces and namespaces. Mixins and
// dictionaries should always generate their members.
if (type != 'interface' && type != 'namespace') return true;
Expand Down Expand Up @@ -665,10 +666,11 @@ class Translator {
static Translator? instance;

Translator(this.packageRoot, this._librarySubDir, this._cssStyleDeclarations,
this._elementTagMap) {
this._elementTagMap,
{required bool generateAll}) {
instance = this;
docProvider = DocProvider.create();
browserCompatData = BrowserCompatData.read();
browserCompatData = BrowserCompatData.read(generateAll: generateAll);
}

void _addOrUpdateInterfaceLike(idl.Interfacelike interfacelike) {
Expand Down Expand Up @@ -702,31 +704,31 @@ class Translator {
...library.partialInterfaces
]) {
final name = interfacelike.name;
bool shouldGenerate;
switch (interfacelike.type) {
case 'interface':
shouldGenerate = browserCompatData.shouldGenerateInterface(name);
if (browserCompatData.shouldGenerateInterface(name)) {
_addOrUpdateInterfaceLike(interfacelike);
_usedTypes.add(interfacelike);
}
break;
case 'namespace':
// Browser compat data doesn't document namespaces that only contain
// constants.
// https://github.com/mdn/browser-compat-data/blob/main/docs/data-guidelines/api.md#namespaces
shouldGenerate = browserCompatData.shouldGenerateInterface(name) ||
if (browserCompatData.shouldGenerateInterface(name) ||
interfacelike.members.toDart
.every((member) => member.type == 'const');
.every((member) => member.type == 'const')) {
_addOrUpdateInterfaceLike(interfacelike);
_usedTypes.add(interfacelike);
}
break;
case 'dictionary':
shouldGenerate = false;
if (BrowserCompatData.generateAll) markTypeAsUsed(name);
break;
default:
throw Exception(
'Unexpected interfacelike type ${interfacelike.type}');
}

if (shouldGenerate) {
_addOrUpdateInterfaceLike(interfacelike);
_usedTypes.add(interfacelike);
}
}
for (final interfacelike in [
...library.interfaceMixins,
Expand Down
3 changes: 3 additions & 0 deletions web_generator/mono_pkg.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,6 @@ stages:
- generate_and_analyze:
- command: dart bin/update_bindings.dart
- analyze: --fatal-infos .
- generate_all_and_analyze:
- command: dart bin/update_bindings.dart --generate-all
- analyze: --fatal-infos .