• Home
  • History
  • Annotate
Name Date Size #Lines LOC

..03-May-2022-

lib/H03-May-2022-

test/H03-May-2022-18,77916,263

.gitignoreH A D11-Apr-201748 54

.gitmodulesH A D11-Apr-2017103 43

.travis.ymlH A D11-Apr-201738 43

LICENSEH A D11-Apr-20171.1 KiB2217

README.mdH A D11-Apr-201722.7 KiB761610

package.jsonH A D11-Apr-2017467 2221

README.md

1
2# WebIDL 2
3
4[![NPM version](https://badge.fury.io/js/webidl2.png)](http://badge.fury.io/js/webidl2)
5
6Purpose
7=======
8
9This is a parser for the [WebIDL](http://dev.w3.org/2006/webapi/WebIDL/) language. If
10you don't know what that is, then you probably don't need it. It is meant to be used
11both in Node and in the browser (the parser likely works in other JS environments, but
12not the test suite).
13
14What of v1?
15-----------
16There was a previous incarnation of this project. I had written it in the most quick
17and dirty manner that was handy because I required it as a dependency in an experiment.
18As these things tend to happen, some people started using that, which then had to be
19maintained. But since it was not built on solid foundations, it was painful to keep
20up to date with the specification, which is a bit of a moving target.
21
22So I started from scratch. Compared to the previous version (which used a parser generator)
23this one is about 6x less code (which translates to 4x smaller minified or 2x smaller
24minizipped) and 4x faster. The test suite is reasonably complete (95% coverage), much more
25than previously. This version is up to date with WebIDL, rather than a couple years' behind.
26It also has *far* better error reporting.
27
28The AST you get from parsing is very similar to the one you got in v1, but some adjustments
29have been made in order to be more systematic, and to map better to what's actually in the spec
30now. If you used v1, you will need to tweak your code but the result ought to be simpler and
31you ought to be able to be a fair bit less defensive against irregularities in the way
32information is represented.
33
34Installation
35============
36
37Just the usual. For Node:
38
39    npm install webidl2
40
41In the browser:
42
43    <script src='webidl2.js'></script>
44
45Documentation
46=============
47
48The API to WebIDL2 is trivial: you parse a string of WebIDL and it returns a syntax tree.
49
50Parsing
51-------
52In Node, that happens with:
53
54    var WebIDL2 = require("webidl2");
55    var tree = WebIDL2.parse("string of WebIDL");
56
57In the browser:
58
59    <script src='webidl2.js'></script>
60    <script>
61      var tree = WebIDL2.parse("string of WebIDL");
62    </script>
63
64Advanced Parsing
65----------------
66
67`parse()` can optionally accept a second parameter, an options object, which can be used to
68modify parsing behavior.
69
70The following options are recognized:
71```javascript
72{
73    allowNestedTypedefs: false #
74}
75```
76And their meanings are as follows:
77
78* `allowNestedTypedefs`: Boolean indicating whether the parser should accept `typedef`s as valid members of `interface`s. This is non-standard syntax and therefore the default is `false`.
79
80Errors
81------
82When there is a syntax error in the WebIDL, it throws an exception object with the following
83properties:
84
85* `message`: the error message
86* `line`: the line at which the error occurred.
87* `input`: a short peek at the text at the point where the error happened
88* `tokens`: the five tokens at the point of error, as understood by the tokeniser
89  (this is the same content as `input`, but seen from the tokeniser's point of view)
90
91The exception also has a `toString()` method that hopefully should produce a decent
92error message.
93
94AST (Abstract Syntax Tree)
95--------------------------
96The `parse()` method returns a tree object representing the parse tree of the IDL.
97Comment and white space are not represented in the AST.
98
99The root of this object is always an array of definitions (where definitions are
100any of interfaces, exceptions, callbacks, etc. — anything that can occur at the root
101of the IDL).
102
103### IDL Type
104
105This structure is used in many other places (operation return types, argument types, etc.).
106It captures a WebIDL type with a number of options. Types look like this and are typically
107attached to a field called `idlType`:
108
109    {
110        "sequence": false,
111        "generic": null,
112        "nullable": false,
113        "array": false,
114        "union": false,
115        "idlType": "void"
116    }
117
118Where the fields are as follows:
119
120* `sequence`: Boolean indicating whether this is a sequence or not. Deprecated. Use
121  `generic` instead.
122* `generic`: String indicating the generic type (e.g. "Promise", "sequence"). `null`
123  otherwise.
124* `nullable`: Boolean indicating whether this is nullable or not.
125* `array`: Either `false` to indicate that it is not an array, or a number for the level of
126  array nesting.
127* `union`: Boolean indicating whether this is a union type or not.
128* `idlType`: Can be different things depending on context. In most cases, this will just
129  be a string with the type name. But the reason this field isn't called "typeName" is
130  because it can take more complex values. If the type is a union, then this contains an
131  array of the types it unites. If it is a generic type, it contains the IDL type
132  description for the type in the sequence, the eventual value of the promise, etc.
133
134#### Interactions between `nullable` and `array`
135
136A more complex data model for our AST would likely represent `Foo[][][]` as a series of
137nested types four levels deep with three anonymous array types eventually containing a
138`Foo` type. But experience shows that such structures are cumbersome to use, and so we
139have a simpler model in which the depth of the array is specified with the `array` field.
140
141This is all fine and well, and in the vast majority of cases is actually simpler. But it
142does run afoul of cases in which it is necessary to distinguish between `Foo[][][]?`,
143`Foo?[][][]`, `Foo[][]?[]`, or even `Foo?[]?[]?[]?`.
144
145For this, when a type is an array type an additional `nullableArray` field is made available
146that captures which of the arrays contain nullable elements. It contains booleans that are
147true if the given array depth contains nullable elements, and false otherwise (mapping that to
148the syntax, and item is true if there is a `?` preceding the `[]`). These examples ought to
149clarify the model:
150
151    Foo[][][]?
152        -> nullable: true
153        -> nullableArray: [false, false, false]
154    Foo?[][][]
155        -> nullable: false
156        -> nullableArray: [true, false, false]
157    Foo[][]?[]
158        -> nullable: false
159        -> nullableArray: [false, false, true]
160    Foo?[]?[]?[]?
161        -> nullable: true
162        -> nullableArray: [true, true, true]
163
164Of particular importance, please note that the overall type is only `nullable` if there is
165a `?` at the end.
166
167### Interface
168Interfaces look like this:
169
170    {
171        "type": "interface",
172        "name": "Animal",
173        "partial": false,
174        "members": [...],
175        "inheritance": null,
176        "extAttrs": [...]
177    },
178    {
179        "type": "interface",
180        "name": "Human",
181        "partial": false,
182        "members": [...],
183        "inheritance": "Animal",
184        "extAttrs": [...]
185    }
186
187The fields are as follows:
188
189* `type`: Always "interface".
190* `name`: The name of the interface
191* `partial`: A boolean indicating whether it's a partial interface.
192* `members`: An array of interface members (attributes, operations, etc.). Empty if there are none.
193* `inheritance`: A string giving the name of an interface this one inherits from, `null` otherwise.
194  **NOTE**: In v1 this was an array, but multiple inheritance is no longer supported so this didn't make
195  sense.
196* `extAttrs`: A list of [extended attributes](#extended-attributes).
197
198### Callback Interfaces
199
200These are captured by the same structure as [Interfaces](#interface) except that
201their `type` field is "callback interface".
202
203### Callback
204
205A callback looks like this:
206
207  {
208      "type": "callback",
209      "name": "AsyncOperationCallback",
210      "idlType": {
211          "sequence": false,
212          "generic": null,
213          "nullable": false,
214          "array": false,
215          "union": false,
216          "idlType": "void"
217      },
218      "arguments": [...],
219      "extAttrs": []
220  }
221
222The fields are as follows:
223
224* `type`: Always "callback".
225* `name`: The name of the callback.
226* `idlType`: An [IDL Type](#idl-type) describing what the callback returns.
227* `arguments`: A list of [arguments](#arguments), as in function paramters.
228* `extAttrs`: A list of [extended attributes](#extended-attributes).
229
230### Dictionary
231
232A dictionary looks like this:
233
234    {
235        "type": "dictionary",
236        "name": "PaintOptions",
237        "partial": false,
238        "members": [
239            {
240                "type": "field",
241                "name": "fillPattern",
242                "required": false,
243                "idlType": {
244                    "sequence": false,
245                    "generic": null,
246                    "nullable": true,
247                    "array": false,
248                    "union": false,
249                    "idlType": "DOMString"
250                },
251                "extAttrs": [],
252                "default": {
253                    "type": "string",
254                    "value": "black"
255                }
256            }
257        ],
258        "inheritance": null,
259        "extAttrs": []
260    }
261
262The fields are as follows:
263
264* `type`: Always "dictionary".
265* `name`: The dictionary name.
266* `partial`: Boolean indicating whether it's a partial dictionary.
267* `members`: An array of members (see below).
268* `inheritance`: A string indicating which dictionary is being inherited from, `null` otherwise.
269* `extAttrs`: A list of [extended attributes](#extended-attributes).
270
271All the members are fields as follows:
272
273* `type`: Always "field".
274* `name`: The name of the field.
275* `required`: Boolean indicating whether this is a [required](https://heycam.github.io/webidl/#required-dictionary-member) field.
276* `idlType`: An [IDL Type](#idl-type) describing what field's type.
277* `extAttrs`: A list of [extended attributes](#extended-attributes).
278* `default`: A [default value](#default-and-const-values), absent if there is none.
279
280### Exception
281
282An exception looks like this:
283
284    {
285        "type": "exception",
286        "name": "HierarchyRequestError",
287        "members": [
288            {
289                "type": "field",
290                "name": "code",
291                "idlType": {
292                    "sequence": false,
293                    "generic": null,
294                    "nullable": false,
295                    "array": false,
296                    "union": false,
297                    "idlType": "unsigned short"
298                },
299                "extAttrs": []
300            }
301        ],
302        "inheritance": "DOMException",
303        "extAttrs": []
304    }
305
306The fields are as follows:
307
308* `type`: Always "exception".
309* `name`: The exception name.
310* `members`: An array of members (constants or fields, where fields are described below).
311* `inheritance`: A string indicating which exception is being inherited from, `null` otherwise.
312* `extAttrs`: A list of [extended attributes](#extended-attributes).
313
314Members that aren't [constants](#constants) have the following fields:
315
316* `type`: Always "field".
317* `name`: The field's name.
318* `idlType`: An [IDL Type](#idl-type) describing what field's type.
319* `extAttrs`: A list of [extended attributes](#extended-attributes).
320
321### Enum
322
323An enum looks like this:
324
325    {
326        "type": "enum",
327        "name": "MealType",
328        "values": [
329            "rice",
330            "noodles",
331            "other"
332        ],
333        "extAttrs": []
334    }
335
336The fields are as follows:
337
338* `type`: Always "enum".
339* `name`: The enum's name.
340* `value`: An array of values (strings).
341* `extAttrs`: A list of [extended attributes](#extended-attributes).
342
343### Typedef
344
345A typedef looks like this:
346
347    {
348        "type": "typedef",
349        "typeExtAttrs": [],
350        "idlType": {
351            "sequence": true,
352            "generic": "sequence",
353            "nullable": false,
354            "array": false,
355            "union": false,
356            "idlType": {
357                "sequence": false,
358                "generic": null,
359                "nullable": false,
360                "array": false,
361                "union": false,
362                "idlType": "Point"
363            }
364        },
365        "name": "PointSequence",
366        "extAttrs": []
367    }
368
369The fields are as follows:
370
371* `type`: Always "typedef".
372* `name`: The typedef's name.
373* `idlType`: An [IDL Type](#idl-type) describing what typedef's type.
374* `extAttrs`: A list of [extended attributes](#extended-attributes).
375* `typeExtAttrs`: A list of [extended attributes](#extended-attributes) that apply to the
376type rather than to the typedef as a whole.
377
378### Implements
379
380An implements definition looks like this:
381
382    {
383        "type": "implements",
384        "target": "Node",
385        "implements": "EventTarget",
386        "extAttrs": []
387    }
388
389The fields are as follows:
390
391* `type`: Always "implements".
392* `target`: The interface that implements another.
393* `implements`: The interface that is being implemented by the target.
394* `extAttrs`: A list of [extended attributes](#extended-attributes).
395
396### Operation Member
397
398An operation looks like this:
399
400    {
401        "type": "operation",
402        "getter": false,
403        "setter": false,
404        "creator": false,
405        "deleter": false,
406        "legacycaller": false,
407        "static": false,
408        "stringifier": false,
409        "idlType": {
410            "sequence": false,
411            "generic": null,
412            "nullable": false,
413            "array": false,
414            "union": false,
415            "idlType": "void"
416        },
417        "name": "intersection",
418        "arguments": [
419            {
420                "optional": false,
421                "variadic": true,
422                "extAttrs": [],
423                "idlType": {
424                    "sequence": false,
425                    "generic": null,
426                    "nullable": false,
427                    "array": false,
428                    "union": false,
429                    "idlType": "long"
430                },
431                "name": "ints"
432            }
433        ],
434        "extAttrs": []
435    }
436
437The fields are as follows:
438
439* `type`: Always "operation".
440* `getter`: True if a getter operation.
441* `setter`: True if a setter operation.
442* `creator`: True if a creator operation.
443* `deleter`: True if a deleter operation.
444* `legacycaller`: True if a legacycaller operation.
445* `static`: True if a static operation.
446* `stringifier`: True if a stringifier operation.
447* `idlType`: An [IDL Type](#idl-type) of what the operation returns. If a stringifier, may be absent.
448* `name`: The name of the operation. If a stringifier, may be `null`.
449* `arguments`: An array of [arguments](#arguments) for the operation.
450* `extAttrs`: A list of [extended attributes](#extended-attributes).
451
452### Attribute Member
453
454An attribute member looks like this:
455
456    {
457        "type": "attribute",
458        "static": false,
459        "stringifier": false,
460        "inherit": false,
461        "readonly": false,
462        "idlType": {
463            "sequence": false,
464            "generic": null,
465            "nullable": false,
466            "array": false,
467            "union": false,
468            "idlType": "RegExp"
469        },
470        "name": "regexp",
471        "extAttrs": []
472    }
473
474The fields are as follows:
475
476* `type`: Always "attribute".
477* `name`: The attribute's name.
478* `static`: True if it's a static attribute.
479* `stringifier`: True if it's a stringifier attribute.
480* `inherit`: True if it's an inherit attribute.
481* `readonly`: True if it's a read-only attribute.
482* `idlType`: An [IDL Type](#idl-type) for the attribute.
483* `extAttrs`: A list of [extended attributes](#extended-attributes).
484
485### Constant Member
486
487A constant member looks like this:
488
489    {
490        "type": "const",
491        "nullable": false,
492        "idlType": "boolean",
493        "name": "DEBUG",
494        "value": {
495            "type": "boolean",
496            "value": false
497        },
498        "extAttrs": []
499    }
500
501The fields are as follows:
502
503* `type`: Always "const".
504* `nullable`: Whether its type is nullable.
505* `idlType`: The type of the constant (a simple type, the type name).
506* `name`: The name of the constant.
507* `value`: The constant value as described by [Const Values](#default-and-const-values)
508* `extAttrs`: A list of [extended attributes](#extended-attributes).
509
510### Serializer Member
511
512Serializers come in many shapes, which are best understood by looking at the
513examples below that map the IDL to the produced AST.
514
515    // serializer;
516    {
517        "type": "serializer",
518        "extAttrs": []
519    }
520
521    // serializer DOMString serialize();
522    {
523        "type": "serializer",
524        "idlType": {
525            "sequence": false,
526            "generic": null,
527            "nullable": false,
528            "array": false,
529            "union": false,
530            "idlType": "DOMString"
531        },
532        "operation": {
533            "name": "serialize",
534            "arguments": []
535        },
536        "extAttrs": []
537    }
538
539    // serializer = { from, to, amount, description };
540    {
541        "type": "serializer",
542        "patternMap": true,
543        "names": [
544            "from",
545            "to",
546            "amount",
547            "description"
548        ],
549        "extAttrs": []
550    }
551
552    // serializer = number;
553    {
554        "type": "serializer",
555        "name": "number",
556        "extAttrs": []
557    }
558
559    // serializer = [ name, number ];
560    {
561        "type": "serializer",
562        "patternList": true,
563        "names": [
564            "name",
565            "number"
566        ],
567        "extAttrs": []
568    }
569
570The common fields are as follows:
571
572* `type`: Always "serializer".
573* `extAttrs`: A list of [extended attributes](#extended-attributes).
574
575For a simple serializer, that's all there is. If the serializer is an operation, it will
576have:
577
578* `idlType`: An [IDL Type](#idl-type) describing what the serializer returns.
579* `operation`: An object with the following fields:
580    * `name`: The name of the operation.
581    * `arguments`: An array of [arguments](#arguments) for the operation.
582
583If the serializer is a pattern map:
584
585* `patternMap`: Always true.
586* `names`: An array of names in the pattern map.
587
588If the serializer is a pattern list:
589
590* `patternList`: Always true.
591* `names`: An array of names in the pattern list.
592
593Finally, if the serializer is a named serializer:
594
595* `name`: The serializer's name.
596
597### Iterator Member
598
599Iterator members look like this
600
601    {
602        "type": "iterator",
603        "getter": false,
604        "setter": false,
605        "creator": false,
606        "deleter": false,
607        "legacycaller": false,
608        "static": false,
609        "stringifier": false,
610        "idlType": {
611            "sequence": false,
612            "generic": null,
613            "nullable": false,
614            "array": false,
615            "union": false,
616            "idlType": "Session2"
617        },
618        "iteratorObject": "SessionIterator",
619        "extAttrs": []
620    }
621
622* `type`: Always "iterator".
623* `iteratorObject`: The string on the right-hand side; absent if there isn't one.
624* the rest: same as on [operations](#operation-member).
625
626### Arguments
627
628The arguments (e.g. for an operation) look like this:
629
630    "arguments": [
631        {
632            "optional": false,
633            "variadic": true,
634            "extAttrs": [],
635            "idlType": {
636                "sequence": false,
637                "generic": null,
638                "nullable": false,
639                "array": false,
640                "union": false,
641                "idlType": "long"
642            },
643            "name": "ints"
644        }
645    ]
646
647The fields are as follows:
648
649* `optional`: True if the argument is optional.
650* `variadic`: True if the argument is variadic.
651* `idlType`: An [IDL Type](#idl-type) describing the type of the argument.
652* `name`: The argument's name.
653* `extAttrs`: A list of [extended attributes](#extended-attributes).
654
655### Extended Attributes
656
657Extended attributes are arrays of items that look like this:
658
659    "extAttrs": [
660        {
661            "name": "TreatNullAs",
662            "arguments": null,
663            "rhs": {
664                "type": "identifier",
665                "value": "EmptyString"
666            }
667        }
668    ]
669
670The fields are as follows:
671
672* `name`: The extended attribute's name.
673* `arguments`: If the extended attribute takes arguments (e.g. `[Foo()]`) or if
674  its right-hand side does (e.g. `[NamedConstructor=Name(DOMString blah)]`) they
675  are listed here. Note that an empty arguments list will produce an empty array,
676  whereas the lack thereof will yield a `null`. If there is an `rhs` field then
677  they are the right-hand side's arguments, otherwise they apply to the extended
678  attribute directly.
679* `rhs`: If there is a right-hand side, this will capture its `type` (which can be
680  "identifier" or "identifier-list") and its `value`.
681* `typePair`: If the extended attribute is a `MapClass` this will capture the
682  map's key type and value type respectively.
683
684### Default and Const Values
685
686Dictionary fields and operation arguments can take default values, and constants take
687values, all of which have the following fields:
688
689* `type`: One of string, number, boolean, null, Infinity, NaN, or sequence.
690
691For string, number, boolean, and sequence:
692
693* `value`: The value of the given type. For sequence, the only possible value is `[]`.
694
695For Infinity:
696
697* `negative`: Boolean indicating whether this is negative Infinity or not.
698
699### `iterable<>`, `legacyiterable<>`, `maplike<>`, `setlike<>` declarations
700
701These appear as members of interfaces that look like this:
702
703        {
704            "type": "maplike", // or "legacyiterable" / "iterable" / "setlike"
705            "idlType": /* One or two types */,
706            "readonly": false, // only for maplike and setlike
707            "extAttrs": []
708        }
709
710The fields are as follows:
711
712* `type`: Always one of "iterable", "legacyiterable", "maplike" or "setlike".
713* `idlType`: An [IDL Type](#idl-type) (or an array of two types) representing the declared type arguments.
714* `readonly`: Whether the maplike or setlike is declared as read only.
715* `extAttrs`: A list of [extended attributes](#extended-attributes).
716
717
718Testing
719=======
720
721In order to run the tests you need to ensure that the widlproc submodule inside `test` is
722initialised and up to date:
723
724    git submodule init
725    git submodule update
726
727Running
728-------
729The test runs with mocha and expect.js. Normally, running mocha in the root directory
730should be enough once you're set up.
731
732Coverage
733--------
734Current test coverage, as documented in `coverage.html`, is 95%. You can run your own
735coverage analysis with:
736
737    jscoverage lib lib-cov
738
739That will create the lib-cov directory with instrumented code; the test suite knows
740to use that if needed. You can then run the tests with:
741
742    JSCOV=1 mocha --reporter html-cov > coverage.html
743
744Note that I've been getting weirdly overescaped results from the html-cov reporter,
745so you might wish to try this instead:
746
747    JSCOV=1 mocha  --reporter html-cov | sed "s/&lt;/</g" | sed "s/&gt;/>/g" | sed "s/&quot;/\"/g" > coverage.html
748
749Browser tests
750-------------
751In order to test in the browser, get inside `test/web` and run `make-web-tests.js`. This
752will generate a `browser-tests.html` file that you can open in a browser. As of this
753writing tests pass in the latest Firefox, Chrome, Opera, and Safari. Testing on IE
754and older versions will happen progressively.
755
756TODO
757====
758
759* add some tests to address coverage limitations
760* add a push API for processors that need to process things like comments
761