Skip to content

Commit c0d73b5

Browse files
[web_generator] Add Support for Parsing IDL Files (#377)
* integrated IDL single file parsing and integration testing * modified interface idl input * Completed support for Single IDL File Parsing Fixes #374 * fixed suffix naming * moved actual output from temp to `.dart_tool` * made minor fixes * Add newline to end of files * Code resolution * updated integration test suite * Resolved all standing fixes to the integration test suite * Update translator.dart
1 parent 4b2f02e commit c0d73b5

34 files changed

+887
-89
lines changed

web_generator/bin/update_idl_bindings.dart

Lines changed: 37 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -67,12 +67,17 @@ $_usage''');
6767

6868
// Run app with `node`.
6969
final generateAll = argResult['generate-all'] as bool;
70+
final inputFiles = argResult['input'] as List<String>;
7071
await runProc(
7172
'node',
7273
[
7374
'main.mjs',
7475
'--idl',
75-
'--output=${p.join(_webPackagePath, 'lib', 'src')}',
76+
for (String inputFile in inputFiles) '--input=$inputFile',
77+
if (inputFiles.isEmpty)
78+
'--output=${p.join(_webPackagePath, 'lib', 'src')}'
79+
else
80+
'--output=${argResult['output'] as String? ?? p.current}',
7681
if (generateAll) '--generate-all',
7782
],
7883
workingDirectory: bindingsGeneratorPath,
@@ -89,16 +94,17 @@ $_usage''');
8994
// delete context file
9095
await contextFile.delete();
9196

92-
// Update readme.
93-
final readmeFile =
94-
File(p.normalize(p.fromUri(Platform.script.resolve('../README.md'))));
97+
if (inputFiles.isEmpty) {
98+
// Update readme.
99+
final readmeFile =
100+
File(p.normalize(p.fromUri(Platform.script.resolve('../README.md'))));
95101

96-
final sourceContent = readmeFile.readAsStringSync();
102+
final sourceContent = readmeFile.readAsStringSync();
97103

98-
final cssVersion = _packageLockVersion(_webRefCss);
99-
final elementsVersion = _packageLockVersion(_webRefElements);
100-
final idlVersion = _packageLockVersion(_webRefIdl);
101-
final versions = '''
104+
final cssVersion = _packageLockVersion(_webRefCss);
105+
final elementsVersion = _packageLockVersion(_webRefElements);
106+
final idlVersion = _packageLockVersion(_webRefIdl);
107+
final versions = '''
102108
$_startComment
103109
| Item | Version |
104110
| --- | --: |
@@ -107,15 +113,16 @@ $_startComment
107113
| `$_webRefIdl` | [$idlVersion](https://www.npmjs.com/package/$_webRefIdl/v/$idlVersion) |
108114
''';
109115

110-
final newContent =
111-
sourceContent.substring(0, sourceContent.indexOf(_startComment)) +
112-
versions +
113-
sourceContent.substring(sourceContent.indexOf(_endComment));
114-
if (newContent == sourceContent) {
115-
print(ansi.styleBold.wrap('No update for readme.'));
116-
} else {
117-
print(ansi.styleBold.wrap('Updating readme for IDL version $idlVersion'));
118-
readmeFile.writeAsStringSync(newContent, mode: FileMode.writeOnly);
116+
final newContent =
117+
sourceContent.substring(0, sourceContent.indexOf(_startComment)) +
118+
versions +
119+
sourceContent.substring(sourceContent.indexOf(_endComment));
120+
if (newContent == sourceContent) {
121+
print(ansi.styleBold.wrap('No update for readme.'));
122+
} else {
123+
print(ansi.styleBold.wrap('Updating readme for IDL version $idlVersion'));
124+
readmeFile.writeAsStringSync(newContent, mode: FileMode.writeOnly);
125+
}
119126
}
120127
}
121128

@@ -161,23 +168,26 @@ final _endComment =
161168
'<!-- END updated by $_scriptPOSIXPath. Do not modify by hand -->';
162169

163170
final _usage = '''
164-
Global Options:
165-
${_parser.usage}
166-
167-
${ansi.styleBold.wrap('IDL Command')}: $_thisScript idl [options]
168-
169-
Usage:
170-
${_parser.commands['idl']?.usage}
171+
${ansi.styleBold.wrap('WebIDL Gen')}:
172+
$_thisScript [options]
171173
172-
${ansi.styleBold.wrap('Typescript Gen Command')}: $_thisScript dts <.d.ts file> [options]
174+
If no IDL file is provided, defaults to the WebIDL definitions needed for package:web
173175
174176
Usage:
175-
${_parser.commands['dts']?.usage}''';
177+
${_parser.usage}''';
176178

177179
final _parser = ArgParser()
178180
..addFlag('help', negatable: false, help: 'Show help information')
179181
..addFlag('update', abbr: 'u', help: 'Update npm dependencies')
180182
..addFlag('compile', defaultsTo: true)
183+
..addOption('output',
184+
abbr: 'o',
185+
help: 'Output directory where bindings will be generated to '
186+
'(defaults to `lib/src` in the web package when no IDL file is provided)')
187+
..addMultiOption('input',
188+
abbr: 'i',
189+
help: 'The input IDL file(s) to read and generate bindings for. '
190+
'If not provided, the default WebIDL definitions will be used.')
181191
..addFlag('generate-all',
182192
negatable: false,
183193
help: 'Generate bindings for all IDL definitions, including experimental '

web_generator/lib/src/dart_main.dart

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,10 @@ void main(List<String> args) async {
3232

3333
if (argResult.wasParsed('idl')) {
3434
await generateIDLBindings(
35-
outputDirectory: argResult['output'] as String,
35+
input: (argResult['input'] as List<String>).isEmpty
36+
? null
37+
: argResult['input'] as Iterable<String>,
38+
output: argResult['output'] as String,
3639
generateAll: argResult['generate-all'] as bool,
3740
languageVersion: Version.parse(languageVersionString),
3841
);
@@ -72,22 +75,46 @@ Future<void> generateJSInteropBindings({
7275
}
7376

7477
Future<void> generateIDLBindings({
75-
required String outputDirectory,
78+
Iterable<String>? input,
79+
required String output,
7680
required bool generateAll,
7781
required Version languageVersion,
7882
}) async {
79-
const librarySubDir = 'dom';
83+
if (input == null) {
84+
// parse dom library as normal
85+
const librarySubDir = 'dom';
86+
87+
ensureDirectoryExists('$output/$librarySubDir');
8088

81-
ensureDirectoryExists('$outputDirectory/$librarySubDir');
89+
final bindings = await generateBindings(packageRoot, librarySubDir,
90+
generateAll: generateAll);
8291

83-
final bindings = await generateBindings(packageRoot, librarySubDir,
84-
generateAll: generateAll);
85-
for (var entry in bindings.entries) {
86-
final libraryPath = entry.key;
87-
final library = entry.value;
92+
for (var entry in bindings.entries) {
93+
final libraryPath = entry.key;
94+
final library = entry.value;
8895

89-
final contents = _emitLibrary(library, languageVersion).toJS;
90-
fs.writeFileSync('$outputDirectory/$libraryPath'.toJS, contents);
96+
final contents = _emitLibrary(library, languageVersion).toJS;
97+
fs.writeFileSync('$output/$libraryPath'.toJS, contents);
98+
}
99+
} else {
100+
// parse individual files
101+
ensureDirectoryExists(output);
102+
103+
final bindings = await generateBindingsForFiles({
104+
for (final file in input)
105+
file: (fs.readFileSync(
106+
file.toJS, JSReadFileOptions(encoding: 'utf-8'.toJS))
107+
as JSString)
108+
.toDart
109+
}, output);
110+
111+
for (var entry in bindings.entries) {
112+
final libraryPath = entry.key;
113+
final library = entry.value;
114+
115+
final contents = _emitLibrary(library, languageVersion).toJS;
116+
fs.writeFileSync('$output/$libraryPath'.toJS, contents);
117+
}
91118
}
92119
}
93120

web_generator/lib/src/generate_bindings.dart

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44

55
import 'dart:js_interop';
66

7+
import 'package:path/path.dart' as p;
8+
9+
import 'js/webidl2.dart' as webidl2;
710
import 'js/webidl_api.dart' as webidl;
811
import 'js/webref_css_api.dart';
912
import 'js/webref_elements_api.dart';
@@ -74,8 +77,8 @@ Future<TranslationResult> generateBindings(
7477
final cssStyleDeclarations = await _generateCSSStyleDeclarations();
7578
final elementHTMLMap = await _generateElementTagMap();
7679
final translator = Translator(
77-
packageRoot, librarySubDir, cssStyleDeclarations, elementHTMLMap,
78-
generateAll: generateAll);
80+
librarySubDir, cssStyleDeclarations, elementHTMLMap,
81+
generateAll: generateAll, packageRoot: packageRoot);
7982
final array = objectEntries(await idl.parseAll().toDart);
8083
for (var i = 0; i < array.length; i++) {
8184
final entry = array[i] as JSArray<JSAny?>;
@@ -86,3 +89,21 @@ Future<TranslationResult> generateBindings(
8689
translator.addInterfacesAndNamespaces();
8790
return translator.translate();
8891
}
92+
93+
Future<TranslationResult> generateBindingsForFiles(
94+
Map<String, String> fileContents, String output) async {
95+
// generate CSS style declarations and element tag map incase they are
96+
// needed for the input files.
97+
final cssStyleDeclarations = await _generateCSSStyleDeclarations();
98+
final elementHTMLMap = await _generateElementTagMap();
99+
final translator = Translator(output, cssStyleDeclarations, elementHTMLMap,
100+
generateAll: true, generateForWeb: false);
101+
102+
for (final file in fileContents.entries) {
103+
final ast = webidl2.parse(file.value);
104+
translator.collect(p.basenameWithoutExtension(file.key), ast);
105+
}
106+
107+
translator.addInterfacesAndNamespaces();
108+
return translator.translate();
109+
}

web_generator/lib/src/js/webidl2.dart

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
@JS('webidl2')
5+
library;
6+
7+
import 'dart:js_interop';
8+
9+
import 'webidl_api.dart' as idl;
10+
11+
@JS()
12+
external JSArray<idl.Node> parse(String contents);

web_generator/lib/src/main.mjs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { createRequire } from 'module';
88
import * as css from '@webref/css';
99
import * as elements from '@webref/elements';
1010
import * as idl from '@webref/idl';
11+
import * as webidl2 from "webidl2";
1112
import * as ts from 'typescript';
1213

1314
const require = createRequire(import.meta.url);
@@ -19,6 +20,7 @@ globalThis.css = css;
1920
globalThis.elements = elements;
2021
globalThis.fs = fs;
2122
globalThis.idl = idl;
23+
globalThis.webidl2 = webidl2;
2224
globalThis.ts = ts;
2325
globalThis.location = { href: `file://${process.cwd()}/` }
2426

web_generator/lib/src/package-lock.json

Lines changed: 2 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

web_generator/lib/src/package.json

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,7 @@
1313
"@webref/css": "^6.11.0",
1414
"@webref/elements": "^2.2.2",
1515
"@webref/idl": "^3.43.1",
16-
"typescript": "^5.8.3"
17-
},
18-
"devDependencies": {
19-
"webidl2": "^24.2.2"
16+
"typescript": "^5.8.3",
17+
"webidl2": "^24.4.1"
2018
}
2119
}

0 commit comments

Comments
 (0)