Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 26 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ Just the usual. For Node:
npm install webidl2
```

In the browser:
In the browser without module support:

```HTML
<script src='webidl2.js'></script>
<script src='./webidl2/dist/webidl2.js'></script>
```

## Documentation
Expand All @@ -35,21 +35,26 @@ WebIDL2 provides two functions: `parse` and `write`.
In Node, that happens with:

```JS
var WebIDL2 = require("webidl2");
var tree = WebIDL2.parse("string of WebIDL");
var text = WebIDL2.write(tree);
const { parse, write, validate } = require("webidl2");
const tree = parse("string of WebIDL");
const text = write(tree);
const validation = validate(tree);
```

In the browser:
```HTML
<script src='webidl2.js'></script>
<script>
var tree = WebIDL2.parse("string of WebIDL");
const tree = WebIDL2.parse("string of WebIDL");
const text = WebIDL2.write(tree);
const validation = WebIDL2.validate(tree);
</script>

<script src='writer.js'></script>
<script>
var text = WebIDL2Writer.write(tree);
<!-- Or when module is supported -->
<script type="module">
import { parse, write, validate } from "./webidl2/index.js";
const tree = parse("string of WebIDL");
const text = write(tree);
const validation = validate(tree);
</script>
```

Expand Down Expand Up @@ -89,11 +94,6 @@ var result = WebIDL2.write(tree, {
* @param type The `wrap()`ed result of references and syntatic bracket strings.
*/
type: type => type,
/**
* Called for each value literals, e.g. `"string"` or `3.12`.
* @param {string} lit The raw literal string.
*/
valueLiteral: lit => lit,
/**
* Receives the return value of `reference()`. String if it's absent.
*/
Expand Down Expand Up @@ -121,6 +121,17 @@ var result = WebIDL2.write(tree, {

"Wrapped value" here will all be raw strings when the `wrap()` callback is absent.

`validate()` returns semantic errors in a string array form:

```js
const validations = validate(tree);
for (const validation of validations) {
console.log(validation);
}
// Validation error on line X: ...
// Validation error on line Y: ...
```

### Errors

When there is a syntax error in the WebIDL, it throws an exception object with the following
Expand Down
33 changes: 16 additions & 17 deletions lib/validator.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,32 +89,31 @@ function* checkInterfaceMemberDuplication(defs) {
}

function* forEachInterface(i) {
const opNames = getOperationNames(i);
const opNames = new Set(getOperations(i).map(op => op.name));
const partials = defs.partials.get(i.name) || [];
const mixins = includesMap.get(i.name) || [];
for (const partial of partials) {
yield* forEachExtension(partial, opNames, i);
}
for (const mixin of mixins) {
yield* forEachExtension(mixin, opNames, i);
for (const ext of [...partials, ...mixins]) {
const additions = getOperations(ext);
yield* forEachExtension(additions, opNames, ext, i);
for (const addition of additions) {
opNames.add(addition.name);
}
}
}

function* forEachExtension(ext, names, base) {
for (const op of ext.members.filter(mem => mem.type === "operation")) {
const name = (op.body && op.body.name) ? op.body.name.value : "";
if (name && names.has(name)) {
const message = `The operation "${name}" has already been defined in the base interface "${base.name}"`;
yield error(ext.source, op.body.tokens.name, ext, message);
function* forEachExtension(additions, existings, ext, base) {
for (const addition of additions) {
const { name } = addition;
if (name && existings.has(name)) {
const message = `The operation "${name}" has already been defined for the base interface "${base.name}" either in itself or in a mixin`;
yield error(ext.source, addition.body.tokens.name, ext, message);
}
}
}

function getOperationNames(i) {
const names = i.members
.filter(({type}) => type === "operation")
.map(op => (op.body && op.body.name) ? op.body.name.value : "");
return new Set(names);
function getOperations(i) {
return i.members
.filter(({type}) => type === "operation");
}

function getIncludesMap() {
Expand Down
3 changes: 3 additions & 0 deletions lib/webidl2.js
Original file line number Diff line number Diff line change
Expand Up @@ -955,6 +955,9 @@ function parseByTokens(source) {
get type() {
return "operation";
}
get name() {
return (this.body && this.body.name && this.body.name.value) || "";
}
get special() {
return untype_token(this.tokens.special);
}
Expand Down
16 changes: 14 additions & 2 deletions test/invalid/baseline/overloads.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
Validation error at line 7, inside `partial interface Base`:
void unique(short num)
^ The operation "unique" has already been defined in the base interface "Base"
^ The operation "unique" has already been defined for the base interface "Base" either in itself or in a mixin
Validation error at line 11, inside `interface mixin Extension`:
void unique(string str)
^ The operation "unique" has already been defined in the base interface "Base"
^ The operation "unique" has already been defined for the base interface "Base" either in itself or in a mixin
Validation error at line 21, inside `interface mixin WebGL2RenderingContextBase`:
void bufferData(GLenum target,
^ The operation "bufferData" has already been defined for the base interface "WebGL2RenderingContext" either in itself or in a mixin
Validation error at line 22, inside `interface mixin WebGL2RenderingContextBase`:
void bufferData(GLenum target,
^ The operation "bufferData" has already been defined for the base interface "WebGL2RenderingContext" either in itself or in a mixin
Validation error at line 23, inside `interface mixin WebGL2RenderingContextBase`:
void bufferData(GLenum target,
^ The operation "bufferData" has already been defined for the base interface "WebGL2RenderingContext" either in itself or in a mixin
Validation error at line 25, inside `interface mixin WebGL2RenderingContextBase`:
void bufferData(GLenum target,
^ The operation "bufferData" has already been defined for the base interface "WebGL2RenderingContext" either in itself or in a mixin
27 changes: 27 additions & 0 deletions test/invalid/idl/overloads.widl
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,30 @@ interface mixin Extension {
};
Base includes Extension;
Base includes Unknown;

// WebGL

interface mixin WebGL2RenderingContextBase
{
// WebGL1:
void bufferData(GLenum target, GLsizeiptr size, GLenum usage);
void bufferData(GLenum target, ArrayBuffer? srcData, GLenum usage);
void bufferData(GLenum target, ArrayBufferView srcData, GLenum usage);
// WebGL2:
void bufferData(GLenum target, ArrayBufferView srcData, GLenum usage, GLuint srcOffset,
optional GLuint length = 0);
};

interface mixin WebGLRenderingContextBase
{
void bufferData(GLenum target, GLsizeiptr size, GLenum usage);
void bufferData(GLenum target, ArrayBuffer? data, GLenum usage);
void bufferData(GLenum target, ArrayBufferView data, GLenum usage);
};

[Exposed=(Window,Worker)]
interface WebGL2RenderingContext
{
};
WebGL2RenderingContext includes WebGLRenderingContextBase;
WebGL2RenderingContext includes WebGL2RenderingContextBase;
3 changes: 3 additions & 0 deletions test/syntax/baseline/allowany.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"members": [
{
"type": "operation",
"name": "g",
"body": {
"name": {
"value": "g",
Expand Down Expand Up @@ -43,6 +44,7 @@
},
{
"type": "operation",
"name": "g",
"body": {
"name": {
"value": "g",
Expand Down Expand Up @@ -107,6 +109,7 @@
},
{
"type": "operation",
"name": "g",
"body": {
"name": {
"value": "g",
Expand Down
1 change: 1 addition & 0 deletions test/syntax/baseline/callback.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
"members": [
{
"type": "operation",
"name": "eventOccurred",
"body": {
"name": {
"value": "eventOccurred",
Expand Down
1 change: 1 addition & 0 deletions test/syntax/baseline/enum.json
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@
},
{
"type": "operation",
"name": "initialize",
"body": {
"name": {
"value": "initialize",
Expand Down
6 changes: 6 additions & 0 deletions test/syntax/baseline/equivalent-decl.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
},
{
"type": "operation",
"name": "getProperty",
"body": {
"name": {
"value": "getProperty",
Expand Down Expand Up @@ -108,6 +109,7 @@
},
{
"type": "operation",
"name": "setProperty",
"body": {
"name": {
"value": "setProperty",
Expand Down Expand Up @@ -256,6 +258,7 @@
},
{
"type": "operation",
"name": "getProperty",
"body": {
"name": {
"value": "getProperty",
Expand Down Expand Up @@ -320,6 +323,7 @@
},
{
"type": "operation",
"name": "setProperty",
"body": {
"name": {
"value": "setProperty",
Expand Down Expand Up @@ -414,6 +418,7 @@
},
{
"type": "operation",
"name": "",
"body": {
"name": null,
"idlType": {
Expand Down Expand Up @@ -477,6 +482,7 @@
},
{
"type": "operation",
"name": "",
"body": {
"name": null,
"idlType": {
Expand Down
4 changes: 4 additions & 0 deletions test/syntax/baseline/generic.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"members": [
{
"type": "operation",
"name": "bar",
"body": {
"name": {
"value": "bar",
Expand Down Expand Up @@ -185,6 +186,7 @@
"members": [
{
"type": "operation",
"name": "getServiced",
"body": {
"name": {
"value": "getServiced",
Expand Down Expand Up @@ -246,6 +248,7 @@
},
{
"type": "operation",
"name": "reloadAll",
"body": {
"name": {
"value": "reloadAll",
Expand Down Expand Up @@ -329,6 +332,7 @@
"members": [
{
"type": "operation",
"name": "default",
"body": {
"name": {
"value": "default",
Expand Down
2 changes: 2 additions & 0 deletions test/syntax/baseline/getter-setter.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
},
{
"type": "operation",
"name": "",
"body": {
"name": null,
"idlType": {
Expand Down Expand Up @@ -104,6 +105,7 @@
},
{
"type": "operation",
"name": "",
"body": {
"name": null,
"idlType": {
Expand Down
3 changes: 3 additions & 0 deletions test/syntax/baseline/identifier-qualified-names.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"members": [
{
"type": "operation",
"name": "createObject",
"body": {
"name": {
"value": "createObject",
Expand Down Expand Up @@ -98,6 +99,7 @@
},
{
"type": "operation",
"name": "",
"body": {
"name": null,
"idlType": {
Expand Down Expand Up @@ -255,6 +257,7 @@
"members": [
{
"type": "operation",
"name": "addEventListener",
"body": {
"name": {
"value": "addEventListener",
Expand Down
6 changes: 6 additions & 0 deletions test/syntax/baseline/indexed-properties.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
},
{
"type": "operation",
"name": "getByIndex",
"body": {
"name": {
"value": "getByIndex",
Expand Down Expand Up @@ -111,6 +112,7 @@
},
{
"type": "operation",
"name": "setByIndex",
"body": {
"name": {
"value": "setByIndex",
Expand Down Expand Up @@ -211,6 +213,7 @@
},
{
"type": "operation",
"name": "removeByIndex",
"body": {
"name": {
"value": "removeByIndex",
Expand Down Expand Up @@ -281,6 +284,7 @@
},
{
"type": "operation",
"name": "get",
"body": {
"name": {
"value": "get",
Expand Down Expand Up @@ -348,6 +352,7 @@
},
{
"type": "operation",
"name": "set",
"body": {
"name": {
"value": "set",
Expand Down Expand Up @@ -445,6 +450,7 @@
},
{
"type": "operation",
"name": "remove",
"body": {
"name": {
"value": "remove",
Expand Down
Loading