Skip to content

Commit d8549a3

Browse files
authored
Add a generate-all flag to emit all bindings (#302)
In the case where a user wants to use an experimental API that we don't include in package:web, it is useful to have the generator emit bindings still so they can copy it over instead of having to write all of it themselves. This also allows us to find problems in our tools with newer bindings before they become standard. - Adds a generate-all flag to the tools and refactors code to incorporate it when determining whether to generate declarations. - Cleans up argument passing so we're always using package:args. - Adds a generate_all_and_analyze to the Dart CI.
1 parent 933a37d commit d8549a3

File tree

12 files changed

+191
-46
lines changed

12 files changed

+191
-46
lines changed

.github/workflows/dart.yml

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,90 @@ jobs:
420420
- job_008
421421
- job_009
422422
job_012:
423+
name: "generate_all_and_analyze; Dart dev; PKG: web_generator; `dart analyze --fatal-infos .`"
424+
runs-on: ubuntu-latest
425+
steps:
426+
- name: Cache Pub hosted dependencies
427+
uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9
428+
with:
429+
path: "~/.pub-cache/hosted"
430+
key: "os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:web_generator;commands:analyze"
431+
restore-keys: |
432+
os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:web_generator
433+
os:ubuntu-latest;pub-cache-hosted;sdk:dev
434+
os:ubuntu-latest;pub-cache-hosted
435+
os:ubuntu-latest
436+
- name: Setup Dart SDK
437+
uses: dart-lang/setup-dart@0a8a0fc875eb934c15d08629302413c671d3f672
438+
with:
439+
sdk: dev
440+
- id: checkout
441+
name: Checkout repository
442+
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332
443+
- id: web_generator_pub_upgrade
444+
name: web_generator; dart pub upgrade
445+
run: dart pub upgrade
446+
if: "always() && steps.checkout.conclusion == 'success'"
447+
working-directory: web_generator
448+
- name: "web_generator; dart analyze --fatal-infos ."
449+
run: dart analyze --fatal-infos .
450+
if: "always() && steps.web_generator_pub_upgrade.conclusion == 'success'"
451+
working-directory: web_generator
452+
needs:
453+
- job_001
454+
- job_002
455+
- job_003
456+
- job_004
457+
- job_005
458+
- job_006
459+
- job_007
460+
- job_008
461+
- job_009
462+
- job_010
463+
- job_011
464+
job_013:
465+
name: "generate_all_and_analyze; Dart dev; PKG: web_generator; `dart bin/update_bindings.dart --generate-all`"
466+
runs-on: ubuntu-latest
467+
steps:
468+
- name: Cache Pub hosted dependencies
469+
uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9
470+
with:
471+
path: "~/.pub-cache/hosted"
472+
key: "os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:web_generator;commands:command_2"
473+
restore-keys: |
474+
os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:web_generator
475+
os:ubuntu-latest;pub-cache-hosted;sdk:dev
476+
os:ubuntu-latest;pub-cache-hosted
477+
os:ubuntu-latest
478+
- name: Setup Dart SDK
479+
uses: dart-lang/setup-dart@0a8a0fc875eb934c15d08629302413c671d3f672
480+
with:
481+
sdk: dev
482+
- id: checkout
483+
name: Checkout repository
484+
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332
485+
- id: web_generator_pub_upgrade
486+
name: web_generator; dart pub upgrade
487+
run: dart pub upgrade
488+
if: "always() && steps.checkout.conclusion == 'success'"
489+
working-directory: web_generator
490+
- name: "web_generator; dart bin/update_bindings.dart --generate-all"
491+
run: dart bin/update_bindings.dart --generate-all
492+
if: "always() && steps.web_generator_pub_upgrade.conclusion == 'success'"
493+
working-directory: web_generator
494+
needs:
495+
- job_001
496+
- job_002
497+
- job_003
498+
- job_004
499+
- job_005
500+
- job_006
501+
- job_007
502+
- job_008
503+
- job_009
504+
- job_010
505+
- job_011
506+
job_014:
423507
name: "dart_fixes; Dart main; PKG: web; `dart fix --compare-to-golden test_fixes`"
424508
runs-on: ubuntu-latest
425509
steps:
@@ -461,3 +545,5 @@ jobs:
461545
- job_009
462546
- job_010
463547
- job_011
548+
- job_012
549+
- job_013

mono_repo.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ merge_stages:
99
- unit_test
1010
- dart_fixes
1111
- generate_and_analyze
12+
- generate_all_and_analyze

tool/ci.sh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,10 @@ for PKG in ${PKGS}; do
7575
echo 'dart bin/update_bindings.dart'
7676
dart bin/update_bindings.dart || EXIT_CODE=$?
7777
;;
78+
command_2)
79+
echo 'dart bin/update_bindings.dart --generate-all'
80+
dart bin/update_bindings.dart --generate-all || EXIT_CODE=$?
81+
;;
7882
format)
7983
echo 'dart format --output=none --set-exit-if-changed .'
8084
dart format --output=none --set-exit-if-changed . || EXIT_CODE=$?

web_generator/CHANGELOG.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
- Initial separation of `web_generator` from `web`.
44
- New IDL interface `RHL` added. `ExtendedAttribute` idl interface updated to
55
expose its `rhs` property and `Interfacelike` idl interface updated to expose
6-
`extAttrs` property. The generator now adds a
6+
`extAttrs` property. The generator now adds a
77
`JS(LegacyNamespace.$extensionTypeName)` annotation on `JS` objects if
88
they've an IDL extended attribute `[LegacyNamespace=Foo]` defined in their IDL
9-
description.
10-
11-
9+
description.
10+
- Added `--generate-all` option to generate all bindings, including experimental
11+
and non-standard APIs.

web_generator/README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,17 @@ definitions:
7575
emit code that is standards track and is not experimental to reduce the number
7676
of breaking changes.
7777

78+
## Generate all bindings
79+
80+
To ignore the compatibility data and emit all members, run:
81+
82+
```shell
83+
dart bin/update_bindings.dart --generate-all
84+
```
85+
86+
This is useful if you want to avoid having to write bindings manually for some
87+
experimental and non-standard APIs.
88+
7889
## Web IDL versions
7990

8091
Based on:

web_generator/bin/update_bindings.dart

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,14 @@ $_usage''');
7878
};
7979

8080
// Run app with `node`.
81+
final generateAll = argResult['generate-all'] as bool;
8182
await _runProc(
8283
'node',
83-
['main.mjs', Platform.script.resolve('../../web/lib/src').path],
84+
[
85+
'main.mjs',
86+
'--output-directory=${Platform.script.resolve('../../web/lib/src').path}',
87+
if (generateAll) '--generate-all',
88+
],
8489
workingDirectory: _bindingsGeneratorPath,
8590
);
8691

@@ -232,4 +237,8 @@ ${_parser.usage}''';
232237
final _parser = ArgParser()
233238
..addFlag('update', abbr: 'u', help: 'Update npm dependencies')
234239
..addFlag('compile', defaultsTo: true)
235-
..addFlag('help', negatable: false);
240+
..addFlag('help', negatable: false)
241+
..addFlag('generate-all',
242+
negatable: false,
243+
help: 'Generate bindings for all IDL definitions, including experimental '
244+
'and non-standard APIs.');

web_generator/lib/src/bcd.dart

Lines changed: 28 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ class BrowserCompatData {
2020
static bool isEventHandlerSupported(String name) =>
2121
_eventHandlers[name]?.any((bcd) => bcd.shouldGenerate) == true;
2222

23-
static BrowserCompatData read() {
23+
static BrowserCompatData read({required bool generateAll}) {
2424
final path =
2525
p.join('node_modules', '@mdn', 'browser-compat-data', 'data.json');
2626
final content = (fs.readFileSync(
@@ -46,7 +46,7 @@ class BrowserCompatData {
4646

4747
for (final symbolName in api.symbolNames) {
4848
final apiInfo = api[symbolName] as Map<String, dynamic>;
49-
final interface = BCDInterfaceStatus(symbolName, apiInfo);
49+
final interface = BCDInterfaceStatus(symbolName, apiInfo, generateAll);
5050
if (interface._sourceFile.startsWith(globalsFilePrefix)) {
5151
// MDN stores global members e.g. `isSecureContext` in the same location
5252
// as the interfaces. These are not interfaces, but rather properties
@@ -67,36 +67,46 @@ class BrowserCompatData {
6767

6868
globals.forEach((name, apiInfo) {
6969
for (final globalInterface in globalInterfaces) {
70-
globalInterface.addProperty(name, apiInfo);
70+
globalInterface.addProperty(name, apiInfo, generateAll);
7171
}
7272
});
7373

74-
return BrowserCompatData(Map.fromIterable(
75-
interfaces,
76-
key: (i) => (i as BCDInterfaceStatus).name,
77-
));
74+
return BrowserCompatData(
75+
Map.fromIterable(
76+
interfaces,
77+
key: (i) => (i as BCDInterfaceStatus).name,
78+
),
79+
generateAll);
7880
}
7981

8082
final Map<String, BCDInterfaceStatus> interfaces;
8183

82-
BrowserCompatData(this.interfaces);
84+
/// Whether to generate all the bindings regardless of property status.
85+
bool generateAll = false;
86+
87+
BrowserCompatData(this.interfaces, this.generateAll);
8388

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

8691
bool shouldGenerateInterface(String name) =>
87-
retrieveInterfaceFor(name)?.shouldGenerate ?? false;
92+
generateAll || (retrieveInterfaceFor(name)?.shouldGenerate ?? false);
8893
}
8994

9095
class BCDInterfaceStatus extends BCDItem {
9196
final Map<String, BCDPropertyStatus> _properties = {};
9297

93-
BCDInterfaceStatus(super.name, super.json) {
98+
late final bool shouldGenerate;
99+
100+
BCDInterfaceStatus(super.name, super.json, bool generateAll) {
94101
for (final symbolName in json.symbolNames) {
95-
addProperty(symbolName, json[symbolName] as Map<String, dynamic>);
102+
addProperty(
103+
symbolName, json[symbolName] as Map<String, dynamic>, generateAll);
96104
}
105+
shouldGenerate = generateAll || (standardTrack && !experimental);
97106
}
98107

99-
void addProperty(String property, Map<String, dynamic> compat) {
108+
void addProperty(
109+
String property, Map<String, dynamic> compat, bool generateAll) {
100110
// Event compatibility data is stored as `<name_of_event>_event`. In order
101111
// to have compatibility data for `onX` properties, we need to replace such
102112
// property names. See https://github.com/mdn/browser-compat-data/blob/main/docs/data-guidelines/api.md#dom-events-eventname_event
@@ -105,12 +115,12 @@ class BCDInterfaceStatus extends BCDItem {
105115
const eventSuffix = '_event';
106116
if (property.endsWith(eventSuffix)) {
107117
property = 'on${property.replaceAll(eventSuffix, '')}';
108-
status = BCDPropertyStatus(property, compat, this);
118+
status = BCDPropertyStatus(property, compat, this, generateAll);
109119
BrowserCompatData._eventHandlers
110120
.putIfAbsent(property, () => {})
111121
.add(status);
112122
} else {
113-
status = BCDPropertyStatus(property, compat, this);
123+
status = BCDPropertyStatus(property, compat, this, generateAll);
114124
}
115125
_properties[property] = status;
116126
}
@@ -119,16 +129,16 @@ class BCDInterfaceStatus extends BCDItem {
119129
if (isStatic) name = '${name}_static';
120130
return _properties[name];
121131
}
122-
123-
bool get shouldGenerate => standardTrack && !experimental;
124132
}
125133

126134
class BCDPropertyStatus extends BCDItem {
127135
final BCDInterfaceStatus parent;
128136

129-
BCDPropertyStatus(super.name, super.json, this.parent);
137+
late final bool shouldGenerate;
130138

131-
bool get shouldGenerate => standardTrack && !experimental;
139+
BCDPropertyStatus(super.name, super.json, this.parent, bool generateAll) {
140+
shouldGenerate = generateAll || (standardTrack && !experimental);
141+
}
132142
}
133143

134144
abstract class BCDItem {

web_generator/lib/src/dart_main.dart

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import 'dart:js_interop';
66

7+
import 'package:args/args.dart';
78
import 'package:code_builder/code_builder.dart' as code;
89
import 'package:dart_style/dart_style.dart';
910

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

2021
void main(List<String> args) async {
21-
await _generateAndWriteBindings(args[0]);
22+
final ArgResults argResult;
23+
argResult = _parser.parse(args);
24+
await _generateAndWriteBindings(
25+
outputDirectory: argResult['output-directory'] as String,
26+
generateAll: argResult['generate-all'] as bool);
2227
}
2328

24-
Future<void> _generateAndWriteBindings(String dir) async {
29+
Future<void> _generateAndWriteBindings(
30+
{required String outputDirectory, required bool generateAll}) async {
2531
const librarySubDir = 'dom';
2632

27-
ensureDirectoryExists('$dir/$librarySubDir');
33+
ensureDirectoryExists('$outputDirectory/$librarySubDir');
2834

29-
final bindings = await generateBindings(packageRoot, librarySubDir);
35+
final bindings = await generateBindings(packageRoot, librarySubDir,
36+
generateAll: generateAll);
3037
for (var entry in bindings.entries) {
3138
final libraryPath = entry.key;
3239
final library = entry.value;
3340

3441
final contents = _emitLibrary(library).toJS;
35-
fs.writeFileSync('$dir/$libraryPath'.toJS, contents);
42+
fs.writeFileSync('$outputDirectory/$libraryPath'.toJS, contents);
3643
}
3744
}
3845

@@ -47,3 +54,11 @@ String _emitLibrary(code.Library library) {
4754
return DartFormatter(languageVersion: DartFormatter.latestLanguageVersion)
4855
.format(source.toString());
4956
}
57+
58+
final _parser = ArgParser()
59+
..addOption('output-directory',
60+
mandatory: true, help: 'Directory where bindings will be generated to.')
61+
..addFlag('generate-all',
62+
negatable: false,
63+
help: 'Generate bindings for all IDL definitions, including experimental '
64+
'and non-standard APIs.');

web_generator/lib/src/generate_bindings.dart

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,11 +69,13 @@ Future<Map<String, Set<String>>> _generateElementTagMap() async {
6969
}
7070

7171
Future<TranslationResult> generateBindings(
72-
String packageRoot, String librarySubDir) async {
72+
String packageRoot, String librarySubDir,
73+
{required bool generateAll}) async {
7374
final cssStyleDeclarations = await _generateCSSStyleDeclarations();
7475
final elementHTMLMap = await _generateElementTagMap();
7576
final translator = Translator(
76-
packageRoot, librarySubDir, cssStyleDeclarations, elementHTMLMap);
77+
packageRoot, librarySubDir, cssStyleDeclarations, elementHTMLMap,
78+
generateAll: generateAll);
7779
final array = objectEntries(await idl.parseAll().toDart);
7880
for (var i = 0; i < array.length; i++) {
7981
final entry = array[i] as JSArray<JSAny?>;

web_generator/lib/src/main.mjs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ globalThis.idl = idl;
2121
globalThis.location = { href: `file://${process.cwd()}/` }
2222

2323
globalThis.dartMainRunner = async function (main, args) {
24-
const dir = process.argv[2];
25-
await main(dir);
24+
const dartArgs = process.argv.slice(2);
25+
await main(dartArgs);
2626
}
2727

2828
async function scriptMain() {

0 commit comments

Comments
 (0)