README.md
1
2# WebIDL 2
3
4[![NPM version](https://badge.fury.io/js/webidl2.svg)](http://badge.fury.io/js/webidl2)
5
6## Purpose
7
8This is a parser for the [WebIDL](http://dev.w3.org/2006/webapi/WebIDL/) language. If
9you don't know what that is, then you probably don't need it. It is meant to be used
10both in Node and in the browser (the parser likely works in other JS environments, but
11not the test suite).
12
13## Installation
14
15Just the usual. For Node:
16
17```Bash
18npm install webidl2
19```
20
21In the browser:
22
23```HTML
24<script src='webidl2.js'></script>
25```
26
27## Documentation
28
29The API to WebIDL2 is trivial: you parse a string of WebIDL and it returns a syntax tree.
30
31### Parsing
32
33In Node, that happens with:
34
35```JS
36var WebIDL2 = require("webidl2");
37var tree = WebIDL2.parse("string of WebIDL");
38```
39
40In the browser:
41```HTML
42<script src='webidl2.js'></script>
43<script>
44 var tree = WebIDL2.parse("string of WebIDL");
45</script>
46```
47
48### Errors
49
50When there is a syntax error in the WebIDL, it throws an exception object with the following
51properties:
52
53* `message`: the error message
54* `line`: the line at which the error occurred.
55* `input`: a short peek at the text at the point where the error happened
56* `tokens`: the five tokens at the point of error, as understood by the tokeniser
57 (this is the same content as `input`, but seen from the tokeniser's point of view)
58
59The exception also has a `toString()` method that hopefully should produce a decent
60error message.
61
62### AST (Abstract Syntax Tree)
63
64The `parse()` method returns a tree object representing the parse tree of the IDL.
65Comment and white space are not represented in the AST.
66
67The root of this object is always an array of definitions (where definitions are
68any of interfaces, dictionaries, callbacks, etc. — anything that can occur at the root
69of the IDL).
70
71### IDL Type
72
73This structure is used in many other places (operation return types, argument types, etc.).
74It captures a WebIDL type with a number of options. Types look like this and are typically
75attached to a field called `idlType`:
76
77```JS
78{
79 "type": "attribute-type",
80 "generic": null,
81 "idlType": "unsigned short",
82 "nullable": false,
83 "union": false,
84 "extAttrs": [...]
85}
86```
87
88Where the fields are as follows:
89
90* `type`: String indicating where this type is used. Can be `null` if not applicable.
91* `generic`: String indicating the generic type (e.g. "Promise", "sequence"). `null`
92 otherwise.
93* `idlType`: Can be different things depending on context. In most cases, this will just
94 be a string with the type name. But the reason this field isn't called "typeName" is
95 because it can take more complex values. If the type is a union, then this contains an
96 array of the types it unites. If it is a generic type, it contains the IDL type
97 description for the type in the sequence, the eventual value of the promise, etc.
98* `nullable`: Boolean indicating whether this is nullable or not.
99* `union`: Boolean indicating whether this is a union type or not.
100* `extAttrs`: A list of [extended attributes](#extended-attributes).
101
102### Interface
103
104Interfaces look like this:
105
106```JS
107{
108 "type": "interface",
109 "name": "Animal",
110 "partial": false,
111 "members": [...],
112 "inheritance": null,
113 "extAttrs": [...]
114}, {
115 "type": "interface",
116 "name": "Human",
117 "partial": false,
118 "members": [...],
119 "inheritance": "Animal",
120 "extAttrs": [...]
121}
122```
123
124The fields are as follows:
125
126* `type`: Always "interface".
127* `name`: The name of the interface.
128* `partial`: A boolean indicating whether it's a partial interface.
129* `members`: An array of interface members (attributes, operations, etc.). Empty if there are none.
130* `inheritance`: A string giving the name of an interface this one inherits from, `null` otherwise.
131 **NOTE**: In v1 this was an array, but multiple inheritance is no longer supported so this didn't make
132 sense.
133* `extAttrs`: A list of [extended attributes](#extended-attributes).
134
135### Interface mixins
136
137Interfaces mixins look like this:
138
139```JS
140{
141 "type": "interface mixin",
142 "name": "Animal",
143 "partial": false,
144 "members": [...],
145 "extAttrs": [...]
146}, {
147 "type": "interface mixin",
148 "name": "Human",
149 "partial": false,
150 "members": [...],
151 "extAttrs": [...]
152}
153```
154
155The fields are as follows:
156
157* `type`: Always "interface mixin".
158* `name`: The name of the interface mixin.
159* `partial`: A boolean indicating whether it's a partial interface mixin.
160* `members`: An array of interface members (attributes, operations, etc.). Empty if there are none.
161* `extAttrs`: A list of [extended attributes](#extended-attributes).
162
163### Namespace
164
165Namespaces look like this:
166
167```JS
168{
169 "type": "namespace",
170 "name": "Console",
171 "partial": false,
172 "members": [...],
173 "extAttrs": [...]
174}
175```
176
177The fields are as follows:
178
179* `type`: Always "namespace".
180* `name`: The name of the namespace.
181* `partial`: A boolean indicating whether it's a partial namespace.
182* `members`: An array of namespace members (attributes and operations). Empty if there are none.
183* `extAttrs`: A list of [extended attributes](#extended-attributes).
184
185### Callback Interfaces
186
187These are captured by the same structure as [Interfaces](#interface) except that
188their `type` field is "callback interface".
189
190### Callback
191
192A callback looks like this:
193
194```JS
195{
196 "type": "callback",
197 "name": "AsyncOperationCallback",
198 "idlType": {
199 "type": "return-type",
200 "sequence": false,
201 "generic": null,
202 "nullable": false,
203 "union": false,
204 "idlType": "void",
205 "extAttrs": []
206 },
207 "arguments": [...],
208 "extAttrs": []
209}
210```
211
212The fields are as follows:
213
214* `type`: Always "callback".
215* `name`: The name of the callback.
216* `idlType`: An [IDL Type](#idl-type) describing what the callback returns.
217* `arguments`: A list of [arguments](#arguments), as in function paramters.
218* `extAttrs`: A list of [extended attributes](#extended-attributes).
219
220### Dictionary
221
222A dictionary looks like this:
223
224```JS
225{
226 "type": "dictionary",
227 "name": "PaintOptions",
228 "partial": false,
229 "members": [{
230 "type": "field",
231 "name": "fillPattern",
232 "required": false,
233 "idlType": {
234 "type": "dictionary-type",
235 "sequence": false,
236 "generic": null,
237 "nullable": true,
238 "union": false,
239 "idlType": "DOMString",
240 "extAttrs": [...]
241 },
242 "extAttrs": [],
243 "default": {
244 "type": "string",
245 "value": "black"
246 }
247 }],
248 "inheritance": null,
249 "extAttrs": []
250}
251```
252
253The fields are as follows:
254
255* `type`: Always "dictionary".
256* `name`: The dictionary name.
257* `partial`: Boolean indicating whether it's a partial dictionary.
258* `members`: An array of members (see below).
259* `inheritance`: A string indicating which dictionary is being inherited from, `null` otherwise.
260* `extAttrs`: A list of [extended attributes](#extended-attributes).
261
262All the members are fields as follows:
263
264* `type`: Always "field".
265* `name`: The name of the field.
266* `required`: Boolean indicating whether this is a [required](https://heycam.github.io/webidl/#required-dictionary-member) field.
267* `idlType`: An [IDL Type](#idl-type) describing what field's type.
268* `extAttrs`: A list of [extended attributes](#extended-attributes).
269* `default`: A [default value](#default-and-const-values), absent if there is none.
270
271### Enum
272
273An enum looks like this:
274
275```JS
276{
277 "type": "enum",
278 "name": "MealType",
279 "values": [
280 { "type": "string", "value": "rice" },
281 { "type": "string", "value": "noodles" },
282 { "type": "string", "value": "other" }
283 ],
284 "extAttrs": []
285}
286```
287
288The fields are as follows:
289
290* `type`: Always "enum".
291* `name`: The enum's name.
292* `values`: An array of values.
293* `extAttrs`: A list of [extended attributes](#extended-attributes).
294
295### Typedef
296
297A typedef looks like this:
298
299```JS
300{
301 "type": "typedef",
302 "idlType": {
303 "type": "typedef-type",
304 "sequence": true,
305 "generic": "sequence",
306 "nullable": false,
307 "union": false,
308 "idlType": {
309 "type": "typedef-type",
310 "sequence": false,
311 "generic": null,
312 "nullable": false,
313 "union": false,
314 "idlType": "Point",
315 "extAttrs": [...]
316 },
317 "extAttrs": [...]
318 },
319 "name": "PointSequence",
320 "extAttrs": []
321}
322```
323
324
325The fields are as follows:
326
327* `type`: Always "typedef".
328* `name`: The typedef's name.
329* `idlType`: An [IDL Type](#idl-type) describing what typedef's type.
330* `extAttrs`: A list of [extended attributes](#extended-attributes).
331
332### Implements
333
334An implements definition looks like this:
335
336```JS
337{
338 "type": "implements",
339 "target": "Node",
340 "implements": "EventTarget",
341 "extAttrs": []
342}
343```
344
345The fields are as follows:
346
347* `type`: Always "implements".
348* `target`: The interface that implements another.
349* `implements`: The interface that is being implemented by the target.
350* `extAttrs`: A list of [extended attributes](#extended-attributes).
351
352### Includes
353
354An includes definition looks like this:
355
356```JS
357{
358 "type": "includes",
359 "target": "Node",
360 "includes": "EventTarget",
361 "extAttrs": []
362}
363```
364
365The fields are as follows:
366
367* `type`: Always "includes".
368* `target`: The interface that includes an interface mixin.
369* `includes`: The interface mixin that is being included by the target.
370* `extAttrs`: A list of [extended attributes](#extended-attributes).
371
372### Operation Member
373
374An operation looks like this:
375```JS
376{
377 "type": "operation",
378 "getter": false,
379 "setter": false,
380 "deleter": false,
381 "static": false,
382 "stringifier": false,
383 "idlType": {
384 "type": "return-type",
385 "sequence": false,
386 "generic": null,
387 "nullable": false,
388 "union": false,
389 "idlType": "void",
390 "extAttrs": []
391 },
392 "name": "intersection",
393 "arguments": [{
394 "optional": false,
395 "variadic": true,
396 "extAttrs": [],
397 "idlType": {
398 "type": "argument-type",
399 "sequence": false,
400 "generic": null,
401 "nullable": false,
402 "union": false,
403 "idlType": "long",
404 "extAttrs": [...]
405 },
406 "name": "ints"
407 }],
408 "extAttrs": []
409}
410```
411
412The fields are as follows:
413
414* `type`: Always "operation".
415* `getter`: True if a getter operation.
416* `setter`: True if a setter operation.
417* `deleter`: True if a deleter operation.
418* `static`: True if a static operation.
419* `stringifier`: True if a stringifier operation.
420* `idlType`: An [IDL Type](#idl-type) of what the operation returns. If a stringifier, may be absent.
421* `name`: The name of the operation. If a stringifier, may be `null`.
422* `arguments`: An array of [arguments](#arguments) for the operation.
423* `extAttrs`: A list of [extended attributes](#extended-attributes).
424
425### Attribute Member
426
427An attribute member looks like this:
428
429```JS
430{
431 "type": "attribute",
432 "static": false,
433 "stringifier": false,
434 "inherit": false,
435 "readonly": false,
436 "idlType": {
437 "type": "attribute-type",
438 "sequence": false,
439 "generic": null,
440 "nullable": false,
441 "union": false,
442 "idlType": "RegExp",
443 "extAttrs": [...]
444 },
445 "name": "regexp",
446 "extAttrs": []
447}
448```
449
450The fields are as follows:
451
452* `type`: Always "attribute".
453* `name`: The attribute's name.
454* `static`: True if it's a static attribute.
455* `stringifier`: True if it's a stringifier attribute.
456* `inherit`: True if it's an inherit attribute.
457* `readonly`: True if it's a read-only attribute.
458* `idlType`: An [IDL Type](#idl-type) for the attribute.
459* `extAttrs`: A list of [extended attributes](#extended-attributes).
460
461### Constant Member
462
463A constant member looks like this:
464
465```JS
466{
467 "type": "const",
468 "nullable": false,
469 "idlType": {
470 "type": "const-type",
471 "sequence": false,
472 "generic": null,
473 "nullable": false,
474 "union": false,
475 "idlType": "boolean"
476 "extAttrs": []
477 },
478 "name": "DEBUG",
479 "value": {
480 "type": "boolean",
481 "value": false
482 },
483 "extAttrs": []
484}
485```
486
487The fields are as follows:
488
489* `type`: Always "const".
490* `nullable`: Whether its type is nullable.
491* `idlType`: An [IDL Type](#idl-type) of the constant that represents a simple type, the type name.
492* `name`: The name of the constant.
493* `value`: The constant value as described by [Const Values](#default-and-const-values)
494* `extAttrs`: A list of [extended attributes](#extended-attributes).
495
496### Arguments
497
498The arguments (e.g. for an operation) look like this:
499
500```JS
501{
502 "arguments": [{
503 "optional": false,
504 "variadic": true,
505 "extAttrs": [],
506 "idlType": {
507 "type": "argument-type",
508 "sequence": false,
509 "generic": null,
510 "nullable": false,
511 "union": false,
512 "idlType": "long",
513 "extAttrs": [...]
514 },
515 "name": "ints"
516 }]
517}
518```
519
520The fields are as follows:
521
522* `optional`: True if the argument is optional.
523* `variadic`: True if the argument is variadic.
524* `idlType`: An [IDL Type](#idl-type) describing the type of the argument.
525* `name`: The argument's name.
526* `extAttrs`: A list of [extended attributes](#extended-attributes).
527
528### Extended Attributes
529
530Extended attributes are arrays of items that look like this:
531
532```JS
533{
534 "extAttrs": [{
535 "name": "TreatNullAs",
536 "arguments": null,
537 "type": "extended-attribute",
538 "rhs": {
539 "type": "identifier",
540 "value": "EmptyString"
541 }
542 }]
543}
544```
545
546The fields are as follows:
547
548* `name`: The extended attribute's name.
549* `arguments`: If the extended attribute takes arguments (e.g. `[Foo()]`) or if
550 its right-hand side does (e.g. `[NamedConstructor=Name(DOMString blah)]`) they
551 are listed here. Note that an empty arguments list will produce an empty array,
552 whereas the lack thereof will yield a `null`. If there is an `rhs` field then
553 they are the right-hand side's arguments, otherwise they apply to the extended
554 attribute directly.
555* `type`: Always `"extended-attribute"`.
556* `rhs`: If there is a right-hand side, this will capture its `type` (which can be
557 "identifier" or "identifier-list") and its `value`.
558
559### Default and Const Values
560
561Dictionary fields and operation arguments can take default values, and constants take
562values, all of which have the following fields:
563
564* `type`: One of string, number, boolean, null, Infinity, NaN, or sequence.
565
566For string, number, boolean, and sequence:
567
568* `value`: The value of the given type, as a string. For sequence, the only possible value is `[]`.
569
570For Infinity:
571
572* `negative`: Boolean indicating whether this is negative Infinity or not.
573
574### `iterable<>`, `legacyiterable<>`, `maplike<>`, `setlike<>` declarations
575
576These appear as members of interfaces that look like this:
577
578```JS
579{
580 "type": "maplike", // or "legacyiterable" / "iterable" / "setlike"
581 "idlType": /* One or two types */ ,
582 "readonly": false, // only for maplike and setlike
583 "extAttrs": []
584}
585```
586
587The fields are as follows:
588
589* `type`: Always one of "iterable", "legacyiterable", "maplike" or "setlike".
590* `idlType`: An array with one or more [IDL Types](#idl-type) representing the declared type arguments.
591* `readonly`: Whether the maplike or setlike is declared as read only.
592* `extAttrs`: A list of [extended attributes](#extended-attributes).
593
594
595## Testing
596
597### Running
598
599The test runs with mocha and expect.js. Normally, running mocha in the root directory
600should be enough once you're set up.
601
602### Coverage
603
604Current test coverage, as documented in `coverage.html`, is 95%. You can run your own
605coverage analysis with:
606
607```Bash
608jscoverage lib lib-cov
609```
610
611That will create the lib-cov directory with instrumented code; the test suite knows
612to use that if needed. You can then run the tests with:
613
614```Bash
615JSCOV=1 mocha --reporter html-cov > coverage.html
616```
617
618Note that I've been getting weirdly overescaped results from the html-cov reporter,
619so you might wish to try this instead:
620
621```Bash
622JSCOV=1 mocha --reporter html-cov | sed "s/</</g" | sed "s/>/>/g" | sed "s/"/\"/g" > coverage.html
623```
624### Browser tests
625
626In order to test in the browser, get inside `test/web` and run `make-web-tests.js`. This
627will generate a `browser-tests.html` file that you can open in a browser. As of this
628writing tests pass in the latest Firefox, Chrome, Opera, and Safari. Testing on IE
629and older versions will happen progressively.
630