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