diff --git a/README.md b/README.md index 247731c6..4d10a35a 100644 --- a/README.md +++ b/README.md @@ -18,10 +18,10 @@ Just the usual. For Node: npm install webidl2 ``` -In the browser: +In the browser without module support: ```HTML - + ``` ## Documentation @@ -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 - - - ``` @@ -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. */ @@ -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 diff --git a/lib/validator.js b/lib/validator.js index 8b961283..67ae58ee 100644 --- a/lib/validator.js +++ b/lib/validator.js @@ -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() { diff --git a/lib/webidl2.js b/lib/webidl2.js index 3570dbec..a40d5e75 100644 --- a/lib/webidl2.js +++ b/lib/webidl2.js @@ -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); } diff --git a/test/invalid/baseline/overloads.txt b/test/invalid/baseline/overloads.txt index b51e8e1a..dc7c87f8 100644 --- a/test/invalid/baseline/overloads.txt +++ b/test/invalid/baseline/overloads.txt @@ -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 diff --git a/test/invalid/idl/overloads.widl b/test/invalid/idl/overloads.widl index 3d62e633..8da22397 100644 --- a/test/invalid/idl/overloads.widl +++ b/test/invalid/idl/overloads.widl @@ -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; diff --git a/test/syntax/baseline/allowany.json b/test/syntax/baseline/allowany.json index 36463a59..364dbfef 100644 --- a/test/syntax/baseline/allowany.json +++ b/test/syntax/baseline/allowany.json @@ -7,6 +7,7 @@ "members": [ { "type": "operation", + "name": "g", "body": { "name": { "value": "g", @@ -43,6 +44,7 @@ }, { "type": "operation", + "name": "g", "body": { "name": { "value": "g", @@ -107,6 +109,7 @@ }, { "type": "operation", + "name": "g", "body": { "name": { "value": "g", diff --git a/test/syntax/baseline/callback.json b/test/syntax/baseline/callback.json index 5164f526..8acba5fb 100644 --- a/test/syntax/baseline/callback.json +++ b/test/syntax/baseline/callback.json @@ -65,6 +65,7 @@ "members": [ { "type": "operation", + "name": "eventOccurred", "body": { "name": { "value": "eventOccurred", diff --git a/test/syntax/baseline/enum.json b/test/syntax/baseline/enum.json index 1ef9964e..b5e9342a 100644 --- a/test/syntax/baseline/enum.json +++ b/test/syntax/baseline/enum.json @@ -104,6 +104,7 @@ }, { "type": "operation", + "name": "initialize", "body": { "name": { "value": "initialize", diff --git a/test/syntax/baseline/equivalent-decl.json b/test/syntax/baseline/equivalent-decl.json index 394fa463..3aea1370 100644 --- a/test/syntax/baseline/equivalent-decl.json +++ b/test/syntax/baseline/equivalent-decl.json @@ -41,6 +41,7 @@ }, { "type": "operation", + "name": "getProperty", "body": { "name": { "value": "getProperty", @@ -108,6 +109,7 @@ }, { "type": "operation", + "name": "setProperty", "body": { "name": { "value": "setProperty", @@ -256,6 +258,7 @@ }, { "type": "operation", + "name": "getProperty", "body": { "name": { "value": "getProperty", @@ -320,6 +323,7 @@ }, { "type": "operation", + "name": "setProperty", "body": { "name": { "value": "setProperty", @@ -414,6 +418,7 @@ }, { "type": "operation", + "name": "", "body": { "name": null, "idlType": { @@ -477,6 +482,7 @@ }, { "type": "operation", + "name": "", "body": { "name": null, "idlType": { diff --git a/test/syntax/baseline/generic.json b/test/syntax/baseline/generic.json index 476c882f..d60f886e 100644 --- a/test/syntax/baseline/generic.json +++ b/test/syntax/baseline/generic.json @@ -7,6 +7,7 @@ "members": [ { "type": "operation", + "name": "bar", "body": { "name": { "value": "bar", @@ -185,6 +186,7 @@ "members": [ { "type": "operation", + "name": "getServiced", "body": { "name": { "value": "getServiced", @@ -246,6 +248,7 @@ }, { "type": "operation", + "name": "reloadAll", "body": { "name": { "value": "reloadAll", @@ -329,6 +332,7 @@ "members": [ { "type": "operation", + "name": "default", "body": { "name": { "value": "default", diff --git a/test/syntax/baseline/getter-setter.json b/test/syntax/baseline/getter-setter.json index f0a2aba6..59b9c09d 100644 --- a/test/syntax/baseline/getter-setter.json +++ b/test/syntax/baseline/getter-setter.json @@ -41,6 +41,7 @@ }, { "type": "operation", + "name": "", "body": { "name": null, "idlType": { @@ -104,6 +105,7 @@ }, { "type": "operation", + "name": "", "body": { "name": null, "idlType": { diff --git a/test/syntax/baseline/identifier-qualified-names.json b/test/syntax/baseline/identifier-qualified-names.json index b4c24c10..3f36b4ac 100644 --- a/test/syntax/baseline/identifier-qualified-names.json +++ b/test/syntax/baseline/identifier-qualified-names.json @@ -34,6 +34,7 @@ "members": [ { "type": "operation", + "name": "createObject", "body": { "name": { "value": "createObject", @@ -98,6 +99,7 @@ }, { "type": "operation", + "name": "", "body": { "name": null, "idlType": { @@ -255,6 +257,7 @@ "members": [ { "type": "operation", + "name": "addEventListener", "body": { "name": { "value": "addEventListener", diff --git a/test/syntax/baseline/indexed-properties.json b/test/syntax/baseline/indexed-properties.json index 31112565..4a9d4cf3 100644 --- a/test/syntax/baseline/indexed-properties.json +++ b/test/syntax/baseline/indexed-properties.json @@ -41,6 +41,7 @@ }, { "type": "operation", + "name": "getByIndex", "body": { "name": { "value": "getByIndex", @@ -111,6 +112,7 @@ }, { "type": "operation", + "name": "setByIndex", "body": { "name": { "value": "setByIndex", @@ -211,6 +213,7 @@ }, { "type": "operation", + "name": "removeByIndex", "body": { "name": { "value": "removeByIndex", @@ -281,6 +284,7 @@ }, { "type": "operation", + "name": "get", "body": { "name": { "value": "get", @@ -348,6 +352,7 @@ }, { "type": "operation", + "name": "set", "body": { "name": { "value": "set", @@ -445,6 +450,7 @@ }, { "type": "operation", + "name": "remove", "body": { "name": { "value": "remove", diff --git a/test/syntax/baseline/namespace.json b/test/syntax/baseline/namespace.json index 569cf403..6037216c 100644 --- a/test/syntax/baseline/namespace.json +++ b/test/syntax/baseline/namespace.json @@ -37,6 +37,7 @@ }, { "type": "operation", + "name": "dotProduct", "body": { "name": { "value": "dotProduct", @@ -131,6 +132,7 @@ }, { "type": "operation", + "name": "crossProduct", "body": { "name": { "value": "crossProduct", diff --git a/test/syntax/baseline/nointerfaceobject.json b/test/syntax/baseline/nointerfaceobject.json index 4b89a1ef..fb7d4704 100644 --- a/test/syntax/baseline/nointerfaceobject.json +++ b/test/syntax/baseline/nointerfaceobject.json @@ -7,6 +7,7 @@ "members": [ { "type": "operation", + "name": "lookupEntry", "body": { "name": { "value": "lookupEntry", diff --git a/test/syntax/baseline/nullableobjects.json b/test/syntax/baseline/nullableobjects.json index 44dfa7c4..baec11e9 100644 --- a/test/syntax/baseline/nullableobjects.json +++ b/test/syntax/baseline/nullableobjects.json @@ -39,6 +39,7 @@ "members": [ { "type": "operation", + "name": "f", "body": { "name": { "value": "f", @@ -105,6 +106,7 @@ }, { "type": "operation", + "name": "f", "body": { "name": { "value": "f", diff --git a/test/syntax/baseline/operation-optional-arg.json b/test/syntax/baseline/operation-optional-arg.json index b6f66ac9..3f768cf1 100644 --- a/test/syntax/baseline/operation-optional-arg.json +++ b/test/syntax/baseline/operation-optional-arg.json @@ -7,6 +7,7 @@ "members": [ { "type": "operation", + "name": "createColor", "body": { "name": { "value": "createColor", diff --git a/test/syntax/baseline/overloading.json b/test/syntax/baseline/overloading.json index 44c2314f..8877b4cf 100644 --- a/test/syntax/baseline/overloading.json +++ b/test/syntax/baseline/overloading.json @@ -39,6 +39,7 @@ "members": [ { "type": "operation", + "name": "f", "body": { "name": { "value": "f", @@ -103,6 +104,7 @@ }, { "type": "operation", + "name": "f", "body": { "name": { "value": "f", @@ -184,6 +186,7 @@ "members": [ { "type": "operation", + "name": "f", "body": { "name": { "value": "f", @@ -248,6 +251,7 @@ }, { "type": "operation", + "name": "f", "body": { "name": { "value": "f", @@ -391,6 +395,7 @@ }, { "type": "operation", + "name": "f", "body": { "name": { "value": "f", @@ -427,6 +432,7 @@ }, { "type": "operation", + "name": "f", "body": { "name": { "value": "f", diff --git a/test/syntax/baseline/overridebuiltins.json b/test/syntax/baseline/overridebuiltins.json index 21aafb5f..75a1788c 100644 --- a/test/syntax/baseline/overridebuiltins.json +++ b/test/syntax/baseline/overridebuiltins.json @@ -41,6 +41,7 @@ }, { "type": "operation", + "name": "lookup", "body": { "name": { "value": "lookup", diff --git a/test/syntax/baseline/record.json b/test/syntax/baseline/record.json index 64c98a14..7dcc8347 100644 --- a/test/syntax/baseline/record.json +++ b/test/syntax/baseline/record.json @@ -7,6 +7,7 @@ "members": [ { "type": "operation", + "name": "foo", "body": { "name": { "value": "foo", @@ -136,6 +137,7 @@ }, { "type": "operation", + "name": "bar", "body": { "name": { "value": "bar", @@ -363,6 +365,7 @@ "members": [ { "type": "operation", + "name": "bar", "body": { "name": { "value": "bar", diff --git a/test/syntax/baseline/reg-operations.json b/test/syntax/baseline/reg-operations.json index 826f3fca..296ee6d6 100644 --- a/test/syntax/baseline/reg-operations.json +++ b/test/syntax/baseline/reg-operations.json @@ -88,6 +88,7 @@ "members": [ { "type": "operation", + "name": "isMouseOver", "body": { "name": { "value": "isMouseOver", @@ -124,6 +125,7 @@ }, { "type": "operation", + "name": "setDimensions", "body": { "name": { "value": "setDimensions", @@ -188,6 +190,7 @@ }, { "type": "operation", + "name": "setDimensions", "body": { "name": { "value": "setDimensions", diff --git a/test/syntax/baseline/replaceable.json b/test/syntax/baseline/replaceable.json index 82c77226..bb8e81df 100644 --- a/test/syntax/baseline/replaceable.json +++ b/test/syntax/baseline/replaceable.json @@ -58,6 +58,7 @@ }, { "type": "operation", + "name": "increment", "body": { "name": { "value": "increment", diff --git a/test/syntax/baseline/sequence.json b/test/syntax/baseline/sequence.json index 9205dd7c..ee457635 100644 --- a/test/syntax/baseline/sequence.json +++ b/test/syntax/baseline/sequence.json @@ -7,6 +7,7 @@ "members": [ { "type": "operation", + "name": "drawPolygon", "body": { "name": { "value": "drawPolygon", @@ -94,6 +95,7 @@ }, { "type": "operation", + "name": "getInflectionPoints", "body": { "name": { "value": "getInflectionPoints", @@ -170,6 +172,7 @@ "members": [ { "type": "operation", + "name": "f1", "body": { "name": { "value": "f1", diff --git a/test/syntax/baseline/static.json b/test/syntax/baseline/static.json index 42d30a6b..75175ee4 100644 --- a/test/syntax/baseline/static.json +++ b/test/syntax/baseline/static.json @@ -144,6 +144,7 @@ }, { "type": "operation", + "name": "triangulate", "body": { "name": { "value": "triangulate", diff --git a/test/syntax/baseline/stringifier-custom.json b/test/syntax/baseline/stringifier-custom.json index b6e33603..d4db6366 100644 --- a/test/syntax/baseline/stringifier-custom.json +++ b/test/syntax/baseline/stringifier-custom.json @@ -99,6 +99,7 @@ }, { "type": "operation", + "name": "", "body": { "name": null, "idlType": { diff --git a/test/syntax/baseline/stringifier.json b/test/syntax/baseline/stringifier.json index 29a64298..7c52da60 100644 --- a/test/syntax/baseline/stringifier.json +++ b/test/syntax/baseline/stringifier.json @@ -7,6 +7,7 @@ "members": [ { "type": "operation", + "name": "", "body": { "name": null, "idlType": { @@ -59,6 +60,7 @@ "members": [ { "type": "operation", + "name": "", "body": null, "extAttrs": null, "special": { diff --git a/test/syntax/baseline/treatasnull.json b/test/syntax/baseline/treatasnull.json index 0eb063a5..511059c4 100644 --- a/test/syntax/baseline/treatasnull.json +++ b/test/syntax/baseline/treatasnull.json @@ -65,6 +65,7 @@ }, { "type": "operation", + "name": "isMemberOfBreed", "body": { "name": { "value": "isMemberOfBreed", diff --git a/test/syntax/baseline/treatasundefined.json b/test/syntax/baseline/treatasundefined.json index 5747e57d..f75081c2 100644 --- a/test/syntax/baseline/treatasundefined.json +++ b/test/syntax/baseline/treatasundefined.json @@ -65,6 +65,7 @@ }, { "type": "operation", + "name": "isMemberOfBreed", "body": { "name": { "value": "isMemberOfBreed", diff --git a/test/syntax/baseline/typedef.json b/test/syntax/baseline/typedef.json index 28f5d7af..b16ea4ec 100644 --- a/test/syntax/baseline/typedef.json +++ b/test/syntax/baseline/typedef.json @@ -238,6 +238,7 @@ }, { "type": "operation", + "name": "pointWithinBounds", "body": { "name": { "value": "pointWithinBounds", @@ -302,6 +303,7 @@ }, { "type": "operation", + "name": "allPointsWithinBounds", "body": { "name": { "value": "allPointsWithinBounds", diff --git a/test/syntax/baseline/typesuffixes.json b/test/syntax/baseline/typesuffixes.json index 15bb661b..997ec212 100644 --- a/test/syntax/baseline/typesuffixes.json +++ b/test/syntax/baseline/typesuffixes.json @@ -7,6 +7,7 @@ "members": [ { "type": "operation", + "name": "test", "body": { "name": { "value": "test", diff --git a/test/syntax/baseline/variadic-operations.json b/test/syntax/baseline/variadic-operations.json index 01974c60..664e5a17 100644 --- a/test/syntax/baseline/variadic-operations.json +++ b/test/syntax/baseline/variadic-operations.json @@ -41,6 +41,7 @@ }, { "type": "operation", + "name": "union", "body": { "name": { "value": "union", @@ -107,6 +108,7 @@ }, { "type": "operation", + "name": "intersection", "body": { "name": { "value": "intersection",